2020牛客暑假多校训练营 (第九场) A,E,F,I,J,K

A Groundhog and 2-Power Representaion


模拟题,直接开个栈模拟一下即可,具体看代码。

#include <iostream>
#include <stdio.h>
#include <stack>
using namespace std;
const int maxn=2e4+5;
char str[maxn];
stack<int>stc1;
stack<char>stc2;
int num[maxn];
int tot;
int ans[185];
int b[185];
int a[65];
void toString(int x)
{
    for(int i=0;i<181;++i)
    b[i]=0;
    b[0]=1;
    for(int i=0;i<x;++i)
    {
        for(int j=0;j<181;++j)
        {
            b[j]*=2;
        }
        for(int j=0;j<181;++j)
        {
            if(b[j]>9)
            {
                b[j+1]++;
                b[j]=b[j]%10;
            }
        }
    }
}
void add()
{
    for(int i=0;i<181;++i)
    {
        ans[i]+=b[i];
        if(ans[i]>9)
        {
            ans[i+1]++;
            ans[i]=ans[i]%10;
        }
    }
}
int main()
{
    a[0]=1;
    for(int i=1;i<=30;++i)
    {
        a[i]=a[i-1]*2;
        //cout<<a[i]<<endl;
    }
    scanf("%s",str);
    for(int i=0;str[i];++i)
    {
        if(str[i]=='2')
        {
            if(!stc2.empty())
            stc1.push(str[i]-'0');
            if(stc2.empty()&&str[i+1]!='(')
            {
                num[++tot]=1;
                toString(1);
                add();
            }
            else
            if(stc2.empty())
            stc1.push(str[i]-'0');
        }
        if(str[i]=='0')
        stc1.push(str[i]-'0');
        if(str[i]=='(')
        stc2.push(str[i]);
        if(str[i]==')')
        {
            int s=0;
            while(stc2.top()!='(')
            {
                stc2.pop();
                s+=stc1.top();
                stc1.pop();
               // cout<<s<<endl;
            }
            stc2.pop();
            s+=stc1.top();
            stc1.pop();
            stc1.pop();
            //cout<<s<<endl;
            //cout<<s<<endl;
            if(stc2.empty())
            {
                //cout<<s<<endl;
                toString(s);
                add();
                continue;
            }
            //cout<<tot<<" "<<a[s]<<endl;
            //cout<<a[s]<<endl;
            stc1.push(a[s]);
        }
        if(str[i]=='+')
        {
            if(!stc2.empty())
            stc2.push(str[i]);
        }
    }
    int len;
    for(int i=180;i>=0;i--)
    {
        if(ans[i]!=0)
        {
            len=i;
            break;
        }
    }
    for(int i=len;i>=0;i--)
    {
        printf("%d",ans[i]);
    }
    printf("\n");
    return 0;
}

E Groundhog Chasing Death


首先可以将x,y进行如下质因子分解。

  • fac[] 为质因子数组
  • cnt[] 为该质因子数量数组

进而可以推出下式。

我们知道,gcd(xi,yj),就是 xi 与 yj 的公共质因子最小数量幂次的乘积,如下。

根据这个式子,可以将原式变为如下表示。

我们将最里面的连乘提到最外面,就可以将连乘转化为幂次求和。

然后,我们枚举 i ,因为此时 i,cntx[k],cnty[k]都是固定的,所以我们可以算出在哪个范围取 i·cntx[k],在哪个范围取 j·cnty[k] 。

因此求和可以直接算出来。

其中,edge=i·cntx[k]/cnty[k]向下取整。
这样,我们就可以在时间复杂度内算出答案。这里还可以改一下边界,min(d,max(c-1,edge)),这样就可以只用中间的式子去计算了。

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;
const ll mod=998244353;
ll a,b,c,d,x,y;
map<ll,pair<ll,ll > >fac;
ll quickpow(ll p,__int128 q)
{
    ll res=1;
    while(q)
    {
        if(q&1)
        res=res*p%mod;
        q>>=1;
        p=p*p%mod;
    }
    return res;
}
void getfac(ll p,bool tag)
{
    for(int i=2;i*i<=p;++i)
    {
        while(p%i==0)
        {
            tag?fac[i].second++:fac[i].first++;
            p/=i;
        }
    }
    if(p!=1)
    tag?fac[p].second++:fac[p].first++;
}
int main()
{
    scanf("%lld%lld%lld%lld%lld%lld",&a,&b,&c,&d,&x,&y);
    getfac(x,0);
    getfac(y,1);
    ll ans=1;
    for(auto k:fac)
    {
        if(!k.second.second)
        continue;
        __int128 res=0;
        for(ll i=a;i<=b;++i)
        {
            ll edge=k.second.first*i/k.second.second;
            edge=min(d,max(c-1,edge));
            res+=(d-edge)*k.second.first*i;
            res+=k.second.second*(edge+c)*(edge-c+1)/2;
        }
        ans=ans*quickpow(k.first,res)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}

F Groundhog Looking Dowdy


我们将所有衣服从小到大排序,然后对于每一个 L ,找最近的 R,使其满足来自于m个不同的天数,这样取 a[R]-a[L] 更新答案,即用尺取实现。

#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int maxn=2e6+5;
const int inf=0x3f3f3f3f;
struct node
{
    int id,val;
}a[maxn];
int n,m,k,x,cnt;
bool cmp(node p,node q)
{
    return p.val<q.val;
}
int vis[maxn];
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&k);
        for(int j=1;j<=k;++j)
        {
            scanf("%d",&x);
            a[++cnt]={i,x};
        }
    }
    sort(a+1,a+1+cnt,cmp);
    int l=1,r=0;
    int res=0;
    int ans=inf;
    bool flag=0;
    while(r<cnt)
    {
        while(res<m)
        {
            r++;
            if(r>cnt)
            {
                flag=1;
                break;
            }
            if(!vis[a[r].id])
            res++;
            vis[a[r].id]++;
        }
        if(flag)
        break;
        ans=min(ans,a[r].val-a[l].val);
        while(res>=m)
        {
            vis[a[l].id]--;
            if(!vis[a[l++].id])
            res--;
            else
            ans=min(ans,a[r].val-a[l].val);
        }
    }
    printf("%d\n",ans);
    return 0;
}

I The Crime-solving Plan of Groundhog


构造方法就是选最小非零元素为第一个数,其它数字由小到大构成第二个数,第一个数字也是非零元素。

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e5+5;
int a[maxn],b[maxn];
int T,n;
void multiply(int x)
{
    for(int i=n-1;i>=1;i--)
    {
        b[i]*=x;
    }
    for(int i=n-1;i>=1;i--)
    {
        if(b[i]>9)
        {
            b[i-1]+=b[i]/10;
            b[i]=b[i]%10;
        }
    }
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        b[0]=0;
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
        scanf("%d",&a[i]);
        sort(a+1,a+1+n);
        int l=1;
        while(!a[l])
        l++;
        int tmp=a[l];
        b[1]=a[l+1];
        for(int i=1;i<l;++i)
        b[i+1]=0;
        for(int i=l+2;i<=n;++i)
        b[i-1]=a[i];
        multiply(tmp);
        int st;
        if(b[0])
        st=0;
        else
        st=1;
        for(int i=st;i<n;++i)
        printf("%d",b[i]);
        puts("");
    }
    return 0;
}

J The Escape Plan of Groundhog


利用前缀和O(n 3)的解决,首先,我们将所有位置为0的点,改为-1,这样我们在之后算贡献的时候,只需要算dp[k-1],dp[k],dp[k+1]即可,因为前缀和可能为负数,所以我们将其初始为 maxn。我们枚举上下两行,再枚举列,如果此时列满足都是1,说明其可以作为边界,先更新答案,再dp++。更新答案只需要算上,dp[pky[k]-1],dp[pky[k]],dp[pky[k]+1],只有这样才是可行的。我们遇到不能满足行都是1时,需要将前面加的贡献从dp中减掉。

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=25e4+2;
const int maxm=505;
int n,m;
int a[maxm][maxm];
int dp[maxn<<1],pky[maxm],sum[maxm][maxm];
int ans;
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)
    {
        int x;
        scanf("%d",&x);
        if(x)
        a[i][j]++;
        else
        a[i][j]--;
        sum[i][j]=sum[i-1][j]+a[i][j];
    }
    pky[0]=maxn;//初始为maxn相当于0
    for(int i=1;i<n;++i)//枚举行
    for(int j=i+1;j<=n;++j)//枚举下一行
    {
        int pre=1;
        for(int k=1;k<=m;++k)//枚举列
        {
            if(a[i][k]^1||a[j][k]^1)//成立说明该行没有连续的1不能作为边界
            {
                for(int l=pre;l<=k;++l)
                if(sum[j][l]-sum[i-1][l]==j-i+1)
                {
                    dp[pky[l]]--;//减去其贡献
                }
                pre=k+1;
                pky[k]=maxn;
                continue;
            }
            if(sum[j][k]-sum[i-1][k]==j-i+1)
            ans+=dp[pky[k-1]]+dp[pky[k-1]-1]+dp[pky[k-1]+1];
            pky[k]=pky[k-1]+sum[j-1][k]-sum[i][k];
            if(sum[j][k]-sum[i-1][k]==j-i+1)
            dp[pky[k]]++;
        }
        for(int l=pre;l<=m;++l)
        if(sum[j][l]-sum[i-1][l]==j-i+1)
        dp[pky[l]]--;
    }
    printf("%d\n",ans);
    return 0;
}

K The Flee Plan of Groundhog


首先,一次bfs,找到逃跑前的位置,然后一次dfs,求出 Orange 到各点的最短时间,最后再来一次dfs,看 Groundhog 到每一个点是否被抓住,如果被抓住,更新答案,并且不再在这条路径上走,如果到了叶子节点,直接以 Orange 到达该叶子节点的时间更新答案。

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn=1e5+5;
int n,t,cnt,tot,wh;
bool vis[maxn];
int ma;
int a[maxn];
int d[maxn];
int q[maxn];
struct node
{
    int to,next;
}edge[maxn<<1];
int head[maxn],pre[maxn];
void add(int x,int y)
{
    edge[++cnt].to=y;
    edge[cnt].next=head[x];
    head[x]=cnt;
}
void bfs()
{
    int hh=0,tt=0;
    q[0]=1;
    vis[1]=1;
    pre[1]=-1;
    while(hh<=tt)
    {
        int t=q[hh++];
        for(int i=head[t];i;i=edge[i].next)
        {
            int ver=edge[i].to;
            if(!vis[ver])
            {
                vis[ver]=1;
                pre[ver]=t;
                if(ver==n)
                return;
                q[++tt]=ver;
            }
        }
    }
}
void dfs1(int u,int fa)
{
    for(int i=head[u];i;i=edge[i].next)
    {
        int ver=edge[i].to;
        if(ver==fa)
        continue;
        d[ver]=d[u]+1;
        dfs1(ver,u);
    }
}
void dfs2(int u,int fa,int cost)
{
    bool flag=0;
    for(int i=head[u];i;i=edge[i].next)
    {
        int ver=edge[i].to;
        if(ver==fa)
        continue;
        flag=1;
        //cout<<ver<<" "<<cost+1<<" "<<d[ver]/2+d[ver]%2<<endl;
        if(cost+1>=((d[ver]/2)+(d[ver]%2)))
        ma=max(ma,cost+1);
        else
        dfs2(ver,u,cost+1);
    }
    if(!flag)
    ma=max(ma,d[u]/2+d[u]%2);
}
int main()
{
    ma=0;
    scanf("%d%d",&n,&t);
    for(int i=1;i<n;++i)
    {
        int x,y;
        scanf("%d %d",&x,&y);
        add(x,y);
        add(y,x);
    }
    bfs();
    for(int i=n;i!=-1;i=pre[i])
    {
        a[++tot]=i;
    }
    if(tot<=t+1)
    {
        puts("0");
        return 0;
    }
    int root=a[tot-t];
    //cout<<root<<endl;
    dfs1(n,-1);
    //for(int i=1;i<=n;++i)
    //cout<<i<<" "<<d[i]<<endl;
    dfs2(root,-1,0);
    printf("%d\n",ma);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计中的实现,以及它们在MATLAB环境中的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用中颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述中提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法中,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用中,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值