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