zoukankan      html  css  js  c++  java
  • 8.27 题解

    先%一发达哥
    T1,其实不难,就是一个简单的dp+矩阵快速幂加个原根优化,其实是模意义之前没做过题,有点懵,一开始思路也光想数学了,就gg了……
    模意义下所有运算都和正常运算一样,只是除变成了乘逆元!!
    定义状态数组f[i][j]表示第i步转移后模数为j的概率,矩阵乘优化,可得80分,正解是把每个数转化为p原根的i次方,别的都一样,会发现这样出来的是循环矩阵,复杂度降为O(logm*mod^2)

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #define LL long long
    #define mod 1000000007
    #define N 1005
    using namespace std;
    LL n,m,p,nn;
    LL f[N],g[N],h[N],D[N],ans,pp[N],id[N],num[N];
    LL qp(LL a,LL b){
        LL ans=1;
        while(b){
            if(b&1)ans=ans*a%mod;
            a=a*a%mod;b>>=1;
        }
        return ans;
    }
    bool bo[N];
    int find(int x){
        for(int i=2;i<=x;i++){
            memset(bo,0,sizeof bo);
            int tim=0,now=1;
            while(tim<x){
                if(bo[now])break;
                bo[now]=1; pp[tim]=now;id[now]=tim;
                now=now*i%p; tim++;
            }
            if(tim==x-1) return i;
        }
    }
    void mp(LL A[N],LL B[N],LL C[N]){
        for(int j=0;j<p-1;j++){
            D[j]=0;
            for(int k=0;k<p-1;k++)
                D[j]=(D[j]+A[k]*B[(j+(p-1)-k)%(p-1)])%mod;
        }
        for(int j=0;j<p-1;j++)C[j]=D[j];
    }
    int main(){
        freopen("rand.in","r",stdin);
        freopen("rand.out","w",stdout);
        scanf("%lld%lld%lld",&n,&m,&p);
        LL root=find(p);
        nn=(int)qp(n,mod-2); 
        int a;
        for(int i=1;i<=n;i++){
            scanf("%d",&a);
            num[id[a]]++;
        }
        for(int i=0;i<p-1;i++)
            num[i]=num[i]*nn%mod;
        f[0]=1;
        for(int j=0;j<p-1;j++)
            g[j]=num[j];
        h[0]=1;
        while(m){
            if(m&1) mp(h,g,h);
            mp(g,g,g); m>>=1;
        }
        mp(f,h,h);
        for(int i=0;i<p-1;i++)
            ans=(ans+h[i]*pp[i])%mod;
        printf("%lld
    ",ans);
        return 0;
    }

    T2:0的情况我们可以先暴力计算出b[1],然后从b[1]出发开始dfs,由某个点的父亲的b[i]推出这个点的b[i],变化的是这个点和父亲的连边的贡献,也就是这条边两侧的点的a[i]之和的差值.
    1的情况就稍微复杂一点.设以x为根的子树中所有a[i]之和为sum(x),S=ni=1a[i],由0的情况可知f[x]=b[x]-b[fa[x]]=S-2*sum[x];dfs一遍可以得到n-1个式子,又b[root]=ni=1sum[i],所以

    S=ni=1f[i]+2b[root]n1

    最后再来一遍dfs就好了

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #define N 100050
    using namespace std;
    int T,n,opt;
    int e=1,head[N];
    int fa[N],sum[N],b[N],a[N],f[N];
    long long all;
    struct edge{
        int u,v,next;
    }ed[2*N];
    void add(int u,int v){
        ed[e].u=u;ed[e].v=v;
        ed[e].next=head[u];
        head[u]=e++;
    }
    void dfs1(int x){
        sum[x]+=a[x];
        for(int i=head[x];i;i=ed[i].next){
            int v=ed[i].v;
            if(v==fa[x])continue;
            fa[v]=x;
            dfs1(v);
            sum[x]+=sum[v];b[x]+=sum[v]+b[v];
        }
    }
    void dfs2(int x){
        for(int i=head[x];i;i=ed[i].next){
            int v=ed[i].v;
            if(v==fa[x])continue;
            b[v]=b[x]-sum[v]+(all-sum[v]);
            dfs2(v);
        }
    }
    void dfs3(int x){
        f[x]=b[x]-b[fa[x]];//f[x]=all-2*sum[x]
        for(int i=head[x];i;i=ed[i].next){
            int v=ed[i].v;
            if(v==fa[x])continue;
            fa[v]=x; dfs3(v);
        }
    }
    void dfs4(int x){
        if(x==1)sum[x]=all;
        else sum[x]=(all-f[x])/2;
        a[x]=sum[x];
        for(int i=head[x];i;i=ed[i].next){
            int v=ed[i].v;
            if(v==fa[x])continue;
            dfs4(v);
            a[x]-=sum[v];
        }
    }
    void init(){
        e=1;all=0;
        memset(head,0,sizeof head);
        memset(fa,0,sizeof fa);
        memset(sum,0,sizeof sum);
        memset(a,0,sizeof a);
        memset(b,0,sizeof b);
        memset(f,0,sizeof f);
    }
    int main(){
        scanf("%d",&T);
        while(T--){
            init();
            scanf("%d",&n); int u,v;
            for(int i=1;i<n;i++){
                scanf("%d%d",&u,&v);
                add(u,v);add(v,u);
            }
            scanf("%d",&opt);
            if(opt==0){
                for(int i=1;i<=n;i++){
                    scanf("%d",&a[i]);
                    all+=a[i];
                }
                dfs1(1); dfs2(1);
                for(int i=1;i<=n;i++)printf("%d ",b[i]);
                printf("
    ");
            }
            if(opt==1){
                for(int i=1;i<=n;i++)
                    scanf("%d",&b[i]);
                dfs3(1);
                for(int i=2;i<=n;i++) all+=f[i];
                all+=2*b[1]; all/=(n-1);
                dfs4(1);
                for(int i=1;i<=n;i++)printf("%d ",a[i]);
                printf("
    ");
            }
        }
        return 0;
    }

    T3,组合数,卡特兰数,dp杂糅
    opt=0:枚举横向移动了多少步.横向移动i步时方案数为
    CinCi/2iC(ni)/2n1
    opt=1:纯卡特兰数
    opt=2:f[i]表示走了i步回到原点的方案数,枚举第一次回到原点时走过的步数j,则此时方案数为4f[ij]catalan(j/21)(减1是为了保证没有第一步就走回来)
    opt=3:依然枚举横向移动了多少步.横向移动i步时,方案数为
    Cincatalan(i/2)catalan((ni)/2)

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #define mod 1000000007
    #define N 100050
    #define LL long long
    using namespace std;
    LL fac[2*N],ans,now,f[1050];
    int n,opt;
    LL qp(LL a,LL b){
        LL ans=1;
        while(b){
            if(b&1)ans=ans*a%mod;
            a=a*a%mod;b>>=1;
        }
        return ans;
    }
    LL C(int a,int b){
        if(!b||b==a)return 1;
        if(b>a)return 0;
        return (fac[a]*qp(fac[a-b],mod-2)%mod)*qp(fac[b],mod-2)%mod;
    }
    LL cal(int x){
        if(x<=0)return 1;
        return C(2*x,x)*qp(x+1,mod-2)%mod;
    }
    int main(){
        scanf("%d%d",&n,&opt);
        if(n&1){printf("0
    ");return 0;}
        fac[1]=1;
        for(int i=2;i<=2*n;i++)fac[i]=fac[i-1]*i%mod;
        if(opt==0){
            for(int i=0;i<=n;i+=2){
                now=(C(n,i)*C(i,i>>1)%mod)*C((n-i),(n-i)>>1)%mod;
                ans=(ans+now)%mod;
            }
            printf("%lld
    ",ans);
            return 0;
        }
        if(opt==1){
            ans=cal(n>>1);
            printf("%lld
    ",ans);
        }
        if(opt==2){
            f[0]=1;
            for(int i=2;i<=n;i+=2)
                for(int j=0;j<=i;j+=2)
                    f[i]=(f[i]+4*f[i-j]*cal((j>>1)-1))%mod;
            printf("%lld
    ",f[n]);
        }
        if(opt==3){
            for(int i=0;i<=n;i+=2){
                now=C(n,i)*cal(i>>1)%mod*cal((n-i)>>1)%mod;
                ans=(ans+now)%mod;
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }

    再贴个考试时65分的傻暴力

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #define mod 1000000007
    using namespace std;
    int n,opt;
    long long f[2][2050][2050];
    int main(){
        scanf("%d%d",&n,&opt);
        if(n&1){
            printf("0
    ");
            return 0;
        }
        if(opt==0){
            int ii=0;
            f[ii][n+1][n+1]=1;
            for(int i=1;i<=n;i++){
                ii^=1;
                for(int j=1;j<=2*n+2;j++)
                    for(int k=1;k<=2*n+2;k++)
                        if(f[ii^1][j][k]){
                            f[ii][j+1][k]=(f[ii][j+1][k]+f[ii^1][j][k])%mod;
                            f[ii][j-1][k]=(f[ii][j-1][k]+f[ii^1][j][k])%mod;
                            f[ii][j][k+1]=(f[ii][j][k+1]+f[ii^1][j][k])%mod;
                            f[ii][j][k-1]=(f[ii][j][k-1]+f[ii^1][j][k])%mod;
                            f[ii^1][j][k]=0;
                        }
            }
            printf("%lld
    ",f[ii][n+1][n+1]);
        }
        if(opt==1){
            int ii=0;
            f[ii][n+1][n+1]=1;
            for(int i=1;i<=n;i++){
                ii^=1;
                for(int j=n;j<=2*n+2;j++)
                    for(int k=n+1;k<n+2;k++)
                        if(f[ii^1][j][k]){
                            f[ii][j+1][k]=(f[ii][j+1][k]+f[ii^1][j][k])%mod;
                            if(j-1>=n+1)
                            f[ii][j-1][k]=(f[ii][j-1][k]+f[ii^1][j][k])%mod;
                            f[ii^1][j][k]=0;
                        }
            }
            printf("%lld
    ",f[ii][n+1][n+1]);
        }
        if(opt==2){
            int ii=0;
            f[ii][n+1][n+1]=1;
            for(int i=1;i<=n;i++){
                ii^=1;
                for(int j=1;j<=2*n+2;j++)
                    for(int k=n+1;k<n+2;k++)
                    {
                        if(j==n+1&&k==n+1)continue;
                        if(f[ii^1][j][k]){
                            f[ii][j+1][k]=(f[ii][j+1][k]+f[ii^1][j][k])%mod;
                            f[ii][j-1][k]=(f[ii][j-1][k]+f[ii^1][j][k])%mod;
                            f[ii^1][j][k]=0;
                        }
                    }
                for(int j=n+1;j<n+2;j++)
                    for(int k=1;k<=2*n+2;k++)
                    {
                        if(j==n+1&&k==n+1)continue;
                        if(f[ii^1][j][k]){
                            f[ii][j][k+1]=(f[ii][j][k+1]+f[ii^1][j][k])%mod;
                            f[ii][j][k-1]=(f[ii][j][k-1]+f[ii^1][j][k])%mod;
                            f[ii^1][j][k]=0;
                        }
                    }
                for(int j=n+1;j<n+2;j++)
                    for(int k=n+1;k<n+2;k++)
                        if(f[ii^1][j][k]){
                            f[ii][j+1][k]=(f[ii][j+1][k]+f[ii^1][j][k])%mod;
                            f[ii][j-1][k]=(f[ii][j-1][k]+f[ii^1][j][k])%mod;
                            f[ii][j][k+1]=(f[ii][j][k+1]+f[ii^1][j][k])%mod;
                            f[ii][j][k-1]=(f[ii][j][k-1]+f[ii^1][j][k])%mod;
                            f[ii^1][j][k]=0;
                        }
            }
            printf("%lld
    ",f[ii][n+1][n+1]);
        }
        if(opt==3){
            int ii=0;
            f[ii][n+1][n+1]=1;
            for(int i=1;i<=n;i++){
                ii^=1;
                for(int j=n+1;j<=2*n+2;j++)
                    for(int k=n+1;k<=2*n+2;k++)
                        if(f[ii^1][j][k]){
                            f[ii][j+1][k]=(f[ii][j+1][k]+f[ii^1][j][k])%mod;
                            f[ii][j-1][k]=(f[ii][j-1][k]+f[ii^1][j][k])%mod;
                            f[ii][j][k+1]=(f[ii][j][k+1]+f[ii^1][j][k])%mod;
                            f[ii][j][k-1]=(f[ii][j][k-1]+f[ii^1][j][k])%mod;
                            f[ii^1][j][k]=0;
                        }
            }
            printf("%lld
    ",f[ii][n+1][n+1]);
        }
        return 0;
    }
  • 相关阅读:
    【转载】C/C++中extern关键字详解
    【转载】extern "C"的用法解析(原博主就是抄百度百科的,不如另外一篇好)
    lua Date和Time
    MySQL-Linux安装
    Hive-0.13安装
    MR案例:单表关联查询
    MR案例:小文件处理方案
    MR案例:链式ChainMapper
    MR案例:定制Partitioner
    MR案例:多文件输出MultipleOutputs
  • 原文地址:https://www.cnblogs.com/Ren-Ivan/p/7746673.html
Copyright © 2011-2022 走看看