ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

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;
}

 

posted on 2016-12-11 16:10  nul  阅读(322)  评论(0编辑  收藏  举报