zoukankan      html  css  js  c++  java
  • uoj#272. 【清华集训2016】石家庄的工人阶级队伍比较坚强

    http://uoj.ac/problem/272

    这题的式子形式是异或卷积的三进制推广,因此可以设计一个类似fwt的变换,这里需要一个三次单位根$w$,满足$w^3\%p==1$且$(1+w+w^2)\%p==0$,对给定的模数,在整数中可能找不到满足要求的w,因此考虑模意义的复数域,发现只要用$a+bfrac{sqrt{3}i}{2}$的形式表示复数,a,b为模p意义下的整数,可以满足要求。时间复杂度$O((m+log(t))3^m)$。

    #include<cstdio>
    typedef long long i64;
    int p,n=1,m,t;
    struct cplx{
        int a,b;
        cplx(int _a=0,int _b=0):a(_a),b(_b){}
        cplx operator+(cplx x)const{return cplx((a+x.a)%p,(b+x.b)%p);}
        cplx operator*(cplx x)const{return cplx((i64(a)*x.a-3ll*b*x.b)%p,(i64(a)*x.b+i64(b)*x.a)%p);}
        cplx operator^(int n)const{
            cplx v(1),x(a,b);
            for(;n;n>>=1,x=x*x)if(n&1)v=v*x;
            return v;
        }
    }A[600007],B[600007];
    void dft(cplx*v,int t){
        cplx w1=cplx((p-1)/2,(p+t)/2),w2=w1*w1;
        for(int i=1;i<n;i*=3){
            for(int j=0;j<n;j+=i*3){
                cplx*a=v+j,*b=a+i,*c=b+i;
                for(int k=0;k<i;++k){
                    cplx a1=a[k],b1=b[k],c1=c[k];
                    a[k]=a1+b1+c1;
                    b[k]=a1+b1*w1+c1*w2;
                    c[k]=a1+b1*w2+c1*w1;
                }
            }
        }
        if(t==-1){
            i64 In=1,I3=(p*((p+1)%3?2:1)+1)/3;
            for(int i=0;i<m;++i)In=In*I3%p;
            for(int i=0;i<n;++i)A[i].a=A[i].a*In%p;
        }
    }
    char ib[10000007],*ip=ib,ob[10000007],*op=ob;
    int _(){
        int x=0;
        while(*ip<48)++ip;
        while(*ip>47)x=x*10+*ip++-48;
        return x;
    }
    void pr(int x){
        if(x<0)x+=p;
        int ss[12],sp=0;
        do ss[++sp]=x%10;while(x/=10);
        while(sp)*op++=ss[sp--]+48;
        *op++=10;
    }
    int v0[33][33];
    void dfs(int w,int u,int t1,int t2){
        if(w==m){
            B[u]=v0[t1][t2];
            return;
        }
        u*=3;
        dfs(w+1,u,t1,t2);
        dfs(w+1,u+1,t1+1,t2);
        dfs(w+1,u+2,t1,t2+1);
    }
    int main(){
        fread(ib,1,sizeof(ib),stdin);
        m=_(),t=_(),p=_();
        for(int i=0;i<m;++i)n*=3;
        for(int i=0;i<n;++i)A[i]=_();
        for(int i=0;i<=m;++i)
        for(int j=0;j<=m-i;++j)v0[i][j]=_();
        dfs(0,0,0,0);
        dft(A,1);
        dft(B,1);
        for(int i=0;i<n;++i)A[i]=A[i]*(B[i]^t);
        dft(A,-1);
        for(int i=0;i<n;++i)pr(A[i].a);
        fwrite(ob,1,op-ob,stdout);
        return 0;
    }
  • 相关阅读:
    node.js基础回顾
    PHP基础回顾之表单(二)
    PHP基础回顾(一)
    知识图谱Knowledge Graph
    Qt addStretch()详解
    Qt实现 QQ好友列表QToolBox
    Qt5
    用户级线程和内核级线程
    TCP状态转换图、滑动窗口、半连接状态、2MSL
    理解tcp顺序释放操作和tcp的半关闭
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7505397.html
Copyright © 2011-2022 走看看