bzoj3992
题解:
求模素数 p 原根的方法:对 p-1 进行素因子分解,记pi为p-1的第i个因子,若恒有a^((p-1)/pi) mod p ≠ 1 成立,则 a 就是 p 的原根。(对于合数求原根,只需把 p-1 换成 phi(p) 即可)
首先比较暴力是f[i][j]表示前i个,乘积为j
然后是n*m^2的
我们可以利用原根将每个数变成g^x
这样就变成了加和
可以利用生成函数的思想
然后分治+fft就可以了
代码:
#include <bits/stdc++.h> using namespace std; #define rint register int #define rep(i,h,t) for(rint i=h;i<=t;i++) #define dep(i,t,h) for(rint i=t;i>=h;i--) #define IL inline const double pi=acos(-1.0); const int N=3e4; int n,m,l,r[N],a[N],b[N],w[N],c[N],g,kk,G=3; int p=1004535809; IL int fsp(int x,int y,int p) { int ans=1; while (y) { if(y&1) ans=1ll*ans*x%p; x=1ll*x*x%p; y>>=1; } return ans; } IL void jf(int &x,int y) { x+=y; if (x>p) x-=p; } IL void fft(int *a,int o) { rep(i,0,n-1) if (i>r[i]) swap(a[i],a[r[i]]); for (int i=1;i<n;i*=2) { int wn=fsp(G,(p-1)/(i*2),p); w[0]=1; rep(j,1,i-1) w[j]=(1ll*w[j-1]*wn)%p; for (int j=0;j<n;j+=(i*2)) { int *x=a+j,*y=a+i+j; for (rint k=0;k<i;k++) { const int t=(1ll*w[k]*y[k])%p; y[k]=x[k]-t; if (y[k]<0) y[k]+=p; x[k]+=t; if (x[k]>p) x[k]-=p; } } } if (o==-1) { reverse(&a[1],&a[n]); for (int i=0,inv=fsp(n,p-2,p);i<n;i++) a[i]=1ll*a[i]*inv%p; rep(i,kk,m) jf(a[i%kk],a[i]),a[i]=0; } } IL void query() { l=0; for (n=1;n<=m;n<<=1) l++; rep(i,0,n-1) r[i]=(r[i/2]/2)|((i&1)<<(l-1)); fft(a,1); fft(b,1); rep(i,0,n-1) a[i]=1ll*a[i]*b[i]%p; fft(a,-1); } IL void get_g(int x) { rep(i,1,x-1) { int j; for (j=1;j<m;j++) if (fsp(i,j,m)==1) break; if (j==m-1) { g=i; break; } } } struct re{ int a[N]; }now; re fsp2(int x) { if (x==1) return(now); re tmp=fsp2(x/2); memcpy(b,tmp.a,sizeof(tmp.a)); memcpy(a,tmp.a,sizeof(tmp.a)); query(); if (x%2) { memcpy(b,c,sizeof(c)); query(); } memcpy(tmp.a,a,sizeof(a)); return(tmp); } int f[N]; int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); ios::sync_with_stdio(false); int x,s; cin>>n>>m>>x>>s; kk=m-1; rep(i,1,s) cin>>a[i]; get_g(m); rep(i,0,m-2) f[fsp(g,i,m)]=i; m*=2; rep(i,1,s) if (a[i]) now.a[f[a[i]]]++,c[f[a[i]]]++; fsp2(n); cout<<(a[f[x]]+p)%p; return 0; }