[NTT 原根 指標 多項式快速冪] BZOJ 3992 [SDOI2015]序列統計
阿新 • • 發佈:2019-01-27
注意到,M 是質數 乘法取個log變加法 也就是取指標
於是對於1 ~M−1 中的每一個數都可以表示成原根的某次冪。
於是乘法可以轉化為原根的冪的加法,
轉移的時候就相當於做多項式乘法了
然後快速冪
又是道數論好題
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; } return *p1++; } inline void read(ll &x){ char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; } const int M=30005; const int P=1004535809; const int G=3; inline ll Pow(ll a,ll b,ll p){ ll ret=1; for (;b;(a*=a)%=p,b>>=1) if (b&1) (ret*=a)%=p; return ret; } inline ll Inv(ll x){ return Pow(x,P-2,P); } ll f[100005]; inline ll GetRoot(ll p,ll phi) { int c=0; for (int i=2;i*i<=phi;i++) if (phi%i==0) f[++c]=i,f[++c]=phi/i; for (int g=2;g<p;g++) { int j; for (j=1;j<=c;j++) if (Pow(g,f[j],p)==1) break; if (j==c+1) return g; } return 0; } ll L,w[2][M],R[M]; ll g,ind[M]; ll n,m,X,S,sp; inline void NTT(ll *a,int r){ for (int i=0;i<n;i++) if (i<R[i]) swap(a[i],a[R[i]]); for (int i=1;i<n;i<<=1) for (int j=0;j<n;j+=(i<<1)) for (int k=0;k<i;k++) { ll x=a[j+k],y=w[r][n/(i<<1)*k]*a[j+k+i]%P; a[j+k]=(x+y)%P; a[j+k+i]=(x-y+P)%P; } if (r==1) for (int i=0,inv=Inv(n);i<n;i++) a[i]=a[i]*inv%P; } struct Poly{ ll a[M]; Poly() { memset(a,0,sizeof(a)); } Poly(ll x) { a[0]=x; } ll& operator [] (const int x) { return a[x]; } Poly& operator *=(const Poly &t){ static ll b[M]; memcpy(b,t.a,sizeof(b)); NTT(a,0),NTT(b,0); for (int i=0;i<n;i++) a[i]=a[i]*b[i]%P; NTT(a,1); for (int i=m-1;i<=(m-2)<<1;i++) (a[i-(m-1)]+=a[i])%=P,a[i]=0; return *this; } friend Poly Pow(Poly a,ll b){ Poly ret(1); for (;b;b>>=1,a*=a) if (b&1) ret*=a; return ret; } }a; int main() { ll t; freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(sp); read(m); read(X); read(S); g=GetRoot(m,m-1); for (n=1;n<=m<<1;n<<=1) L++; for(int i=0;i<n;i++) R[i]=(R[i>>1]>>1)|((i&1)<<(L-1)); for (int i=0,now=1;i<m-1;i++,(now*=g)%=m) ind[now]=i; w[0][0]=w[0][n]=1; t=Pow(G,(P-1)/n,P); for (int i=1;i<n;i++) w[0][i]=w[0][i-1]*t%P; for (int i=0;i<=n;i++) w[1][i]=w[0][n-i]; for (int i=1;i<=S;i++) { read(t); if (t) a[ind[t]]=1; } printf("%lld\n",Pow(a,sp)[ind[X]]); return 0; }