• bzoj3992: [SDOI2015]序列统计


    Description

    小C有一个集合S,里面的元素都是小于M的非负整数。他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S。
    小C用这个生成器生成了许多这样的数列。但是小C有一个问题需要你的帮助:给定整数x,求所有可以生成出的,且满足数列中所有数的乘积mod M的值等于x的不同的数列的有多少个。小C认为,两个数列{Ai}和{Bi}不同,当且仅当至少存在一个整数i,满足Ai≠Bi。另外,小C认为这个问题的答案可能很大,因此他只需要你帮助他求出答案mod 1004535809的值就可以了。

    Input

    一行,四个整数,N、M、x、|S|,其中|S|为集合S中元素个数。第二行,|S|个整数,表示集合S中的所有元素。

    Output

    一行,一个整数,表示你求出的种类数mod 1004535809的值。

    将S中元素和x取以m的某个原根为底的离散对数之后转化为生成函数的n次幂在%(m-1)=x的位置的系数和,可以用快速幂套ntt计算

    #include<cstdio>
    #include<algorithm>
    typedef long long i64;
    const int P=1004535809,g=3;
    int n,m,x,s,v0[8007],v1[8007],N=2,K=0,r[17777];
    int rp[8007],rw[8007];
    i64 pow(i64 a,int n){
        i64 v=1;
        for(;n;a=a*a%P,n>>=1)if(n&1)v=v*a%P;
        return v;
    }
    void ntt(i64*a,int t){
        static i64 e[17777];
        for(int i=0;i<N;++i)if(i>r[i])std::swap(a[i],a[r[i]]);
        for(int i=1;i<N;i<<=1){
            i64 w=pow(g,(t*(P-1)/(i<<1)+P-1)%(P-1));
            e[0]=1;
            for(int j=1;j<i;++j)e[j]=e[j-1]*w%P;
            for(int j=0;j<N;j+=i<<1){
                for(int k=0;k<i;++k){
                    i64 x=a[j+k],y=a[j+k+i]*e[k]%P;
                    a[j+k]=(x+y)%P;
                    a[j+k+i]=(x-y)%P;
                }
            }
        }
        if(t<0){
            i64 I=pow(N,P-2);
            for(int i=0;i<N;++i)a[i]=a[i]*I%P;
        }
    }
    void mul(int*a,int*b){
        static i64 A[17777],B[17777];
        for(int i=0;i<m;++i)A[i]=a[i];
        for(int i=m;i<N;++i)A[i]=0;
        ntt(A,1);
        if(a!=b){
            for(int i=0;i<m;++i)B[i]=b[i];
            for(int i=m;i<N;++i)B[i]=0;
            ntt(B,1);
            for(int i=0;i<N;++i)A[i]=A[i]*B[i]%P;
        }else for(int i=0;i<N;++i)A[i]=A[i]*A[i]%P;
        ntt(A,-1);
        for(int i=0;i<m-1;++i)a[i]=(A[i]+A[i+m-1])%P;
    }
    int root(int n){
        if(n==2)return 1;
        for(int i=2;i<n;++i){
            for(int j=1,c=1;j<n-1;++j){
                c=c*i%n;
                if(c==1)goto o;
            }
            return i;
            o:;
        }
    }
    int main(){
        scanf("%d%d%d%d",&n,&m,&x,&s);
        rp[0]=1;
        rp[1]=root(m);
        for(int i=2;i<m-1;++i)rp[i]=rp[i-1]*rp[1]%m;
        for(int i=0;i<m-1;++i)rw[rp[i]]=i;
        for(int i=0,a;i<s;++i){
            scanf("%d",&a);
            a%=m;
            if(a)++v0[rw[a]];
        }
        for(;N<=m*2+3;N<<=1,++K);
        for(int i=1;i<N;++i)r[i]=r[i>>1]>>1|(i&1)<<K;
        v1[0]=1;
        for(;n;mul(v0,v0),n>>=1)if(n&1)mul(v1,v0);
        printf("%d",(v1[rw[x]]+P)%P);
        return 0;
    }
  • 相关阅读:
    乐器、音乐与声学
    函数的功能与坐标轴的理解
    函数的功能与坐标轴的理解
    波、波长与频率
    波、波长与频率
    长方体的研究
    彻底理解线索二叉树
    SSH框架总结(框架分析+环境搭建+实例源代码下载)
    深入浅出WPF 第一部分(3)
    iPad 3g版完美实现打电话功能(phoneitipad破解)
  • 原文地址:https://www.cnblogs.com/ccz181078/p/6159801.html
Copyright © 2020-2023  润新知