BZOJ 3992: [SDOI2015]序列统计
NTT模板题
#include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #define ll long long using namespace std; const int N=20000; const int mod=1004535809; int L,M,n,m,x,s,w,len,lenf,X,vis[N],rev[N]; ll h[N],a[N],b[N],q[N]; ll pow(ll a,ll b,ll mod){ a%=mod; ll ans=1; while (b){ if (b&1) ans=ans*a%mod; a=a*a%mod; b=b>>1; } return ans; } int calc_w(int x){ if (x==2) return 1; for (int i=2; i; i++){ int flag=1; for (int j=2; j*j<x; j++) if (pow(i,(x-1)/j,x)==1){ flag=0; break; } if (flag) return i; } } void NTT(ll *a,int n,int opt){ 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){ ll wn=pow(3,(mod-1)/(i<<1),mod); for (int j=0; j<n; j+=(i<<1)){ ll w=1; for (int k=0; k<i; k++,w=w*wn%mod){ ll x=a[j+k],y=w*a[j+k+i]%mod; a[j+k]=(x+y)%mod,a[j+k+i]=(x-y+mod)%mod; } } } if (opt==-1) reverse(a+1,a+n); } void mul(ll h[N],ll q[N]){ for (int i=0; i<len; i++) a[i]=h[i]%mod; for (int i=0; i<len; i++) b[i]=q[i]%mod; NTT(a,len,1); NTT(b,len,1); for (int i=0; i<len; i++) a[i]=a[i]*b[i]%mod; NTT(a,len,-1); ll inv=pow(len,mod-2,mod); for (int i=0; i<len; i++) a[i]=a[i]*inv%mod; for (int i=0; i<lenf; i++) h[i]=(a[i]+a[i+lenf])%mod; } void solve(int x){ h[0]=1; while (x){ if (x&1) mul(h,q); x>>=1; mul(q,q); } } int main(){ scanf("%d%d%d%d",&n,&m,&X,&s); w=calc_w(m); for (int i=1; i<=s; i++){ int x; scanf("%d",&x); vis[x]=1; } int pos=-1; for (int i=0,j=1; i<m-1; i++,j=j*w%m){ if (vis[j]) q[i]=1; if (j==X) pos=i; } lenf=m-1; M=lenf*2,len=1,L=0; while (len<=M) len<<=1,L++; for (int i=0; i<len; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1)); solve(n); if (pos!=-1) printf("%lld\n",h[pos]); else printf("0\n"); return 0; }