HDU-5730 Shell Necklace (CDQ+FFT/NTT)

HDU-5730(CDQ+FFT/NTT)

题意:将长度为\(n\)的序列分成若干段,每段\([l,r]\)的权值为\(a_{r-l+1}\),一种分法的权值为所有段的乘积,求所有可能的分法的权值和

根据题意可以得到简单\(dp\)

\(dp_0=1,dp_i=\sum_0^{i-1}dp_j \cdot a_{i-j}\)

可以看到是一个\(i-j\)形式的作差卷积

但是直接卷积我们无法保证先求出了\(dp_j\),所有可以用\(CDQ\)分治优化,复杂度\(n\log^2 n\)

具体实现见代码

#include<bits/stdc++.h>
using namespace std;

#define reg register
typedef long long ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)

template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); } 
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); } 

char IO;
int rd(){
	int s=0,f=0;
	while(!isdigit(IO=getchar())) if(IO=='-') f=1;
	do s=(s<<1)+(s<<3)+(IO^'0');
	while(isdigit(IO=getchar()));
	return f?-s:s;
}

const double PI=acos(-1);

const int N=(1<<18)+4,P=313;

int n;
int a[N],dp[N];
struct Cp{
	double x,y;
	Cp operator + (const Cp t) const { return (Cp){x+t.x,y+t.y}; }
	Cp operator - (const Cp t) const { return (Cp){x-t.x,y-t.y}; }
	Cp operator * (const Cp t) const { return (Cp){x*t.x-y*t.y,x*t.y+y*t.x}; }
} A[N],B[N];

Cp w[N];
int rev[N];
void FFT(int n,Cp *a,Cp *w){
	rep(i,1,n-1) if(rev[i]>i) swap(a[i],a[rev[i]]);
	for(reg int i=1;i<n;i<<=1) {
		int len=i*2;
		for(reg int l=0;l<n;l+=len) {
			for(reg int j=l;j<l+i;++j) {
				Cp t=a[j+i]*w[n/len*(j-l)];
				a[j+i]=a[j]-t;
				a[j]=a[j]+t;
			}
		}
	}
}

void Solve(int l,int r){ 
	if(l==r) return;
	int mid=(l+r)>>1;
	Solve(l,mid); //先求出左边所有的
    
	int R=1,c=-1;
	while(R<=r-l+1) R<<=1,c++;
	rep(i,1,R) rev[i]=(rev[i>>1]>>1)|((i&1)<<c);
	w[0]=(Cp){1,0};
	w[1]=(Cp){cos(2*PI/R),sin(2*PI/R)};
	rep(i,2,R) w[i]=w[i-1]*w[1];
	rep(i,l,mid) A[i-l]=(Cp){1.0*dp[i],0};
	rep(i,1,r-l+1) B[i]=(Cp){1.0*a[i],0};
	FFT(R,A,w),FFT(R,B,w);
	rep(i,0,R) w[i].y=-w[i].y,A[i]=A[i]*B[i];
	FFT(R,A,w);
	rep(i,mid+1,r) dp[i]=(dp[i]+ll(A[i-l].x/R+0.5))%P;
	rep(i,0,R) A[i].x=A[i].y=B[i].x=B[i].y=0;
    //让左边已经求出来的向右边转移
    
	Solve(mid+1,r);
    //让右边之间转移
}

int main(){
	while(~scanf("%d",&n) && n) {
		rep(i,1,n) a[i]=rd()%P,dp[i]=0;
		dp[0]=1;
		Solve(0,n);
		printf("%d\n",dp[n]);
	}
}




posted @ 2019-12-26 12:09  chasedeath  阅读(191)  评论(0编辑  收藏  举报