BZOJ3992: [SDOI2015]序列统计【NTT+原根+DP】

3992: [SDOI2015]序列统计

【题目描述】

传送门

【题解】

我们可以写出DP式,F[i][j∗a[k]]+=F[i−1][j]F[i][j*a[k]]+=F[i-1][j]F[i][ja[k]]+=F[i1][j]

初始状态F[0][0]=1F[0][0]=1F[0][0]=1

对于上式我们很难处理,如果我们可以将相乘改成相加,就可以套NTT了。

我们设ggg为mod m意义下的原根。

j=gbjj=g^bjj=gbja[k]=gba[k]a[k]=g^{ba[k]}a[k]=gba[k]

上式就可以写成F[i][gbj+ba[k]]+=F[i−1][gbj]F[i][g^{bj+ba[k]}]+=F[i-1][g^{bj}]F[i][gbj+ba[k]]+=F[i1][gbj]

也就是F[i][bj+ba[k]]+=F[i−1][bj]F[i][bj+ba[k]]+=F[i-1][bj]F[i][bj+ba[k]]+=F[i1][bj]

这不就是卷积的形式了吗,直接套NTT就可以了

【代码如下】

#include
#include
using namespace std;
const int MAXN=8005,MOD=1004535809;
int Len,lg2,g,inv,pos,T,m,X,n,rev[MAXN<<2],Mu[MAXN<<2],a[MAXN<<2],F[MAXN<<2],G[MAXN<<2],NI;bool vis[MAXN];
int qsm(int x,int b,int p){
	int Mul=1;
	for(;b;b>>=1,x=1ll*x*x%p) if(b&1) Mul=1ll*Mul*x%p;
	return Mul;
}
int Cal(){//求m的原根
	if(m==2) return 1;
	for(int i=2;;i++){
		bool f=1;
		for(int j=2;j*j>1]>>1)|((i&1)<<(lg2-1));}
void NTT(int *A,int opt){
	for(int i=0;i>=1,Mul(a,a)) if(T&1) Mul(Mu,a);}
int main(){
	scanf("%d%d%d%d",&T,&m,&X,&n);
	for(int i=1,x;i<=n;i++) scanf("%d",&x),vis[x]=1;
	g=Cal();
	for(int i=0,x=1;i

转载于:https://www.cnblogs.com/XSamsara/p/10547916.html

你可能感兴趣的:(数据结构与算法)