题解:求m的原根,把乘法转化成加法,然后用NTT加速动态规划
听说这是循环卷积???并不会啊,留个坑。
NTT连板子都不熟
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=1000009; typedef long long Lint; const Lint mm2=1004535809; int n,m,fin,mm; Lint g; int ref[maxn]; void Getg(){ for(g=2;g<mm;++g){ Lint tmp=1; int fla=1; for(int i=1;i<mm-1;++i){ tmp=tmp*g%mm; if(tmp==1){ fla=0;break; } } if(fla)break; } Lint tmp=1;ref[1]=0; for(int i=1;i<mm-1;++i){ tmp=tmp*g%mm; ref[tmp]=i; } } Lint Ksm(Lint a,Lint p){ Lint ret=1; for(;p;p>>=1,a=a*a%mm2){ if(p&1)ret=ret*a%mm2; } return ret; } Lint a[maxn]; Lint b[maxn]; Lint ret[maxn]; int l,rev[maxn]; void NTT(Lint *a,int f,int n){ for(int i=0;i<n;++i)if(i<rev[i])swap(a[i],a[rev[i]]); for(int i=1;i<n;i<<=1){ int p=i+i; Lint wn=Ksm(3,mm2/p); if(f==-1)wn=Ksm(wn,mm2-2); for(int j=0;j<n;j+=p){ Lint w=1; for(int k=0;k<i;++k,w=w*wn%mm2){ Lint x=a[j+k],y=a[j+k+i]*w%mm2; a[j+k]=(x+y)%mm2;a[j+k+i]=(x-y+mm2)%mm2; } } } if(f==-1){ Lint inv=Ksm(n,mm2-2); for(int i=0;i<n;++i)a[i]=a[i]*inv%mm2; } } void Getans(int p){ m=mm+mm-4; int n; for(n=1;n<=m;n<<=1)l++; for(int i=0;i<n;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1)); ret[0]=1; for(;p;p>>=1){ if(p&1){ for(int i=0;i<n;++i)b[i]=a[i]; NTT(ret,1,n);NTT(b,1,n); for(int i=0;i<n;++i)ret[i]=ret[i]*b[i]%mm2; NTT(ret,-1,n); for(int i=mm-1;i<n;++i){ ret[i%(mm-1)]+=ret[i];ret[i]=0; } for(int i=0;i<mm-1;++i)ret[i]%=mm2; } for(int i=0;i<n;++i)b[i]=a[i]; NTT(a,1,n);NTT(b,1,n); for(int i=0;i<n;++i)a[i]=a[i]*b[i]%mm2; NTT(a,-1,n); for(int i=mm-1;i<n;++i){ a[i%(mm-1)]+=a[i];a[i]=0; } for(int i=0;i<mm-1;++i)a[i]%=mm2; // for(int i=0;i<n;++i)cout<<a[i]<<‘ ‘; // cout<<endl; } } int main(){ scanf("%d%d%d%d",&n,&mm,&fin,&m); Getg(); while(m--){ int x;scanf("%d",&x); if(x!=0)a[ref[x]]++; } Getans(n); printf("%lld\n",ret[ref[fin]]%mm2); return 0; }