[SDOI2015]序列统计(NTT+求原根)

题目

[SDOI2015]序列统计

挺好的题!!!

做法

\(f[i][j]\)为第\(i\)个数前缀积在模\(M\)意义下为\(j\)

显然是可以快速幂的:$$f[2*i][j]=\sum\limits_{ab\equiv j(mod~ M)}f[i][a]\cdot f[i][b]$$

时间复杂度\(O(m^2 log n)\)

考虑转换到对数上则可以化乘为加,而\(M\)为质数,原根\(g\)\(g_0^{m-2}\)恰好对应\([1,m-1]\)

我们用这些代替数\(g^A\equiv a,g^B\equiv b,g^J\equiv j(mod~m)\)
相当于把\([1,m-1]\)通过这种方法映射到\([0,m-2]\),再进行数组初始化

\[f[2*i][j]=\sum\limits_{g^{A+B}\equiv g^J(mod~ M)}f[i][a]\cdot f[i][b] \]

根据费马小定理\(g^a\equiv g^{a~mod~M-1}(mod~M)\),则:$$f[2*i][j]=\sum\limits_{g^{A+BmodM-1}= g^{Jmod M-1}}f[i][a]\cdot f[i][b]$$

\[f[2*i][j]=\sum\limits_{A+B\equiv J(mod~ M-1)}f[i][a]\cdot f[i][b] \]

则化成了卷积的形式,而后面的取模,我们先正常做一下卷积,然后\(f[i][j]=f[i][j]+f[i][j+M-1]\)

Code

#include<bits/stdc++.h>
typedef int LL;
const LL Mod=1004535809,maxn=1e6+9,G=3;
inline LL Read(){
	LL x(0),f(1); char c=getchar();
	while(c<'0' || c>'9'){
		if(c=='-') f=-1; c=getchar();
	}
	while(c>='0' && c<='9'){
		x=(x<<3)+(x<<1)+c-'0'; c=getchar();
	}return x*f;
}
LL n,m,g,x,num;
LL prime[maxn],r[maxn],c[maxn],d[maxn],pos[maxn],F[maxn],H[maxn];
inline LL Pow(LL base,LL b,LL mod){
	LL sum(1);
	while(b){
		if(b&1) sum=1ll*sum*base%mod; base=1ll*base*base%mod; b>>=1;
	}return sum;
}
inline LL Get_g(LL N){
	LL p(--N),tot(0);
	for(LL i=2;i*i<=N;++i){
		if(N%i==0){
		    while(N%i==0) N/=i;
		    prime[++tot]=i;
		}
	}
	if(N>1) prime[++tot]=N;
	LL now(2);
	while(true){
		bool flag(false);
		for(LL i=1;i<=tot;++i)
		    if(Pow(now,p/prime[i],p+1)==1){
		    	flag=true;
		    	break;
			}
		if(!flag) return now;
		++now;
	}
}
inline LL Init(LL N){
	LL limit(1),len(0);
	while(limit<N){
		limit<<=1; ++len;
	}
	for(LL i=0;i<limit;++i) r[i]=(r[i>>1]>>1)|((i&1)<<len-1);
	return limit;
}
inline void NTT(LL *a,LL limit,LL type,LL mod=Mod){
	for(LL i=0;i<limit;++i) if(i<r[i]) std::swap(a[i],a[r[i]]);
	for(LL mid=1;mid<limit;mid<<=1){
		LL wn(Pow(G,(mod-1)/(mid<<1),mod));
		if(type==-1) wn=Pow(wn,mod-2,mod);
		for(LL R=mid<<1,j=0;j<limit;j+=R){
			for(LL k=0,w=1;k<mid;++k,w=1ll*w*wn%mod){
				LL x(a[j+k]),y(1ll*w*a[j+mid+k]%mod);
				a[j+k]=1ll*(x+y)%mod;
				a[j+mid+k]=1ll*(x-y+mod)%mod;
			}
		}
	}
	if(type==-1){
		LL now(Pow(limit,mod-2,mod));
		for(LL i=0;i<limit;++i) a[i]=1ll*a[i]*now%mod;
	}
}
inline void Mul(LL *a,LL *b,LL limit,LL N,LL mod=Mod){
	for(LL i=0;i<limit;++i) c[i]=a[i];
	for(LL i=0;i<limit;++i) d[i]=b[i];
	NTT(c,limit,1); NTT(d,limit,1);
	for(LL i=0;i<limit;++i) c[i]=1ll*c[i]*d[i]%mod;
	NTT(c,limit,-1);
	for(LL i=0;i<N-1;++i) c[i]=1ll*(c[i]+c[i+N-1])%mod;
	for(LL i=0;i<N-1;++i) a[i]=c[i];
}
int main(){
	n=Read(); m=Read(); x=Read(); num=Read();
	g=Get_g(m);
	for(LL i=0;i<m-1;++i) pos[Pow(g,i,m)]=i;
	for(LL i=1;i<=num;++i){
		LL val(Read());
		if(val) ++F[pos[val]];
	}
	H[pos[1]]=1;
	LL limit(Init(2*m));
	while(n){
		if(n&1) Mul(H,F,limit,m); Mul(F,F,limit,m); n>>=1;
	}
	printf("%d\n",H[pos[x]]);
	return 0;
}
posted @ 2019-06-13 20:02  y2823774827y  阅读(175)  评论(0编辑  收藏  举报