令
fi,j
表示前
i
个数乘积为
由于
m
<script type="math/tex" id="MathJax-Element-211">m</script> 是质数,可以用原根使乘法转换为加法,然后用快速幂+NTT加速即可。
#include<bits/stdc++.h>
using namespace std;
const int N=16400;
const int P=1004535809;
const int G=3;
int k,n,m,p,M;
int ind[N];
int t[N],l,x,y;
int a[N],b[N],r[N];
inline void Add(int& x,int y){
x=(x+y)%P;
}
inline int Pow(int x,int y,int z){
int Ans=1;
for(;y;y>>=1,x=1ll*x*x%z)
if(y&1)Ans=1ll*Ans*x%z;
return Ans;
}
inline int Getg(int n){
for(int i=2;i<n-1;i++)if(!((n-1)%i))t[++l]=i;
for(int i=2;;i++){
int j=1;
for(;j<=l;j++)if(Pow(i,t[j],n)==1)break;
if(j>l)return i;
}
}
inline void NTT(int* a,int n,int d){
for(int i=0;i<n;i++)if(r[i]>i)swap(a[i],a[r[i]]);
for(int i=1;i<n;i<<=1){
int wn=Pow(G,d==1?(P-1)/(i<<1):P-1-(P-1)/(i<<1),P);
for(int j=0;j<n;j+=i<<1){
int w=1;
for(int k=0;k<i;k++){
int x=a[j+k],y=1ll*a[j+k+i]*w%P;
a[j+k]=(x+y)%P;a[j+k+i]=(x-y)%P;
w=1ll*w*wn%P;
}
}
}
if(d==-1){
int inv=Pow(n,P-2,P);
for(int i=0;i<n;i++)a[i]=1ll*a[i]*inv%P;
}
}
int main(){
scanf("%d%d%d%d",&n,&m,&y,&p);
for(int i=0,j=1,g=Getg(m);i<m-1;i++,j=j*g%m)ind[j]=i;
while(p--){
scanf("%d",&x);
if(x)a[ind[x]]=1;
}
m--;
for(l=0,M=1;M<(m<<1);M<<=1)l++;
for(int i=0;i<M;i++)r[i]=(r[i>>1]>>1)|((i&1)<<l-1);
b[0]=1;
for(;n;n>>=1){
NTT(a,M,1);
if(n&1){
NTT(b,M,1);
for(int i=0;i<M;i++)b[i]=1ll*b[i]*a[i]%P;
NTT(b,M,-1);
for(int i=m;i<M;i++)Add(b[i%m],b[i]),b[i]=0;
}
for(int i=0;i<M;i++)a[i]=1ll*a[i]*a[i]%P;
NTT(a,M,-1);
for(int i=m;i<M;i++)Add(a[i%m],a[i]),a[i]=0;
}
cout<<(b[ind[y]]+P)%P<<endl;
return 0;
}