• HDU5730 Shell Necklace(DP + CDQ分治 + FFT)


    题目

    Source

    http://acm.hdu.edu.cn/showproblem.php?pid=5730

    Description

    Perhaps the sea‘s definition of a shell is the pearl. However, in my view, a shell necklace with n beautiful shells contains the most sincere feeling for my best lover Arrietty, but even that is not enough.

    Suppose the shell necklace is a sequence of shells (not a chain end to end). Considering i continuous shells in the shell necklace, I know that there exist different schemes to decorate the i shells together with one declaration of love.

    I want to decorate all the shells with some declarations of love and decorate each shell just one time. As a problem, I want to know the total number of schemes.

    Input

    There are multiple test cases(no more than 20 cases and no more than 1 in extreme case), ended by 0.

    For each test cases, the first line contains an integer n, meaning the number of shells in this shell necklace, where 1≤n≤105. Following line is a sequence with n non-negative integer a1,a2,…,an, and ai≤107 meaning the number of schemes to decorate i continuous shells together with a declaration of love.

    Output

    For each test case, print one line containing the total number of schemes module 313(Three hundred and thirteen implies the march 13th, a special and purposeful day).

    Sample Input

    3
    1 3 7
    4
    2 2 2 2
    0

    Sample Output

    14
    54

    分析

    题目大概说已知连续i(1<=i<=n)个贝壳组合成一段项链的方案数a[i],求组合成包含n个贝壳的项链的总方案数。

    • dp[i]表示组合成包含i个贝壳的项链的总方案数
    • 转移:dp[i]=Σdp[i-j]*a[j](1<=j<=i)

    直接枚举转移的话时间复杂度O(n2),是不行的。

    其实这个转移方程是个比较特殊的卷积形式,可以用FFT去求,但是从1到n依次求的话时间复杂度是O(n2logn)。

    而利用CQD分治,每次治的过程累加左半区间内各个已经求得dp值的状态对右半区间各个状态的贡献,这个贡献就是那个方程用FFT求即可,这样时间复杂度由主定理可知是O(nlog2n)。


    这是个很经典的题目吧,虽然现在才做。。

    代码

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define INF (1<<30)
    #define MAXN 333333
    const double PI=acos(-1.0);
     
    struct Complex{
    	double real,imag;
    	Complex(double _real,double _imag):real(_real),imag(_imag){}
    	Complex(){}
    	Complex operator+(const Complex &cp) const{
    		return Complex(real+cp.real,imag+cp.imag);
    	}
    	Complex operator-(const Complex &cp) const{
    		return Complex(real-cp.real,imag-cp.imag);
    	}
    	Complex operator*(const Complex &cp) const{
    		return Complex(real*cp.real-imag*cp.imag,real*cp.imag+cp.real*imag);
    	}
    	void setValue(double _real=0,double _imag=0){
    		real=_real; imag=_imag;
    	}
    };
     
    int len;
    Complex wn[MAXN],wn_anti[MAXN];
     
    void FFT(Complex y[],int op){
    	for(int i=1,j=len>>1,k; i<len-1; ++i){
    		if(i<j) swap(y[i],y[j]);
    		k=len>>1;
    		while(j>=k){
    			j-=k;
    			k>>=1;
    		}
    		if(j<k) j+=k;
    	}
    	for(int h=2; h<=len; h<<=1){
    		Complex Wn=(op==1?wn[h]:wn_anti[h]);
    		for(int i=0; i<len; i+=h){
    			Complex W(1,0);
    			for(int j=i; j<i+(h>>1); ++j){
    				Complex u=y[j],t=W*y[j+(h>>1)];
    				y[j]=u+t;
    				y[j+(h>>1)]=u-t;
    				W=W*Wn;
    			}
    		}
    	}
    	if(op==-1){
    		for(int i=0; i<len; ++i) y[i].real/=len;
    	}
    }
    void Convolution(Complex A[],Complex B[],int n){
    	for(len=1; len<(n<<1); len<<=1);
    	for(int i=n; i<len; ++i){
    		A[i].setValue();
    		B[i].setValue();
    	}
    	
    	FFT(A,1); FFT(B,1);
    	for(int i=0; i<len; ++i){
    		A[i]=A[i]*B[i];
    	}
    	FFT(A,-1);
    }
    
    int a[111111],d[111111];
    Complex A[MAXN],B[MAXN];
    
    void cdq(int l,int r){
    	if(l==r){
    		d[l]+=a[l];
    		d[l]%=313;
    		return;
    	}
    	int mid=l+r>>1;
    	cdq(l,mid);
    
    	for(int i=l; i<=mid; ++i) A[i-l].setValue(d[i]);
    	for(int i=0; i<=r-l; ++i) B[i].setValue(a[i]);
    	for(int i=mid-l+1; i<=r-l; ++i) A[i].setValue();
    	Convolution(A,B,r-l+1);
    	for(int i=mid+1; i<=r; ++i){
    		d[i]+=((long long)(A[i-l].real+0.5))%313;
    		d[i]%=313;
    	}
    	
    	cdq(mid+1,r);
    }
    
    int main(){
    	for(int i=0; i<MAXN; ++i){
    		wn[i].setValue(cos(2.0*PI/i),sin(2.0*PI/i));
    		wn_anti[i].setValue(wn[i].real,-wn[i].imag);
    	}
    	int n;
    	while(~scanf("%d",&n) && n){
    		for(int i=1; i<=n; ++i){
    			scanf("%d",a+i);
    			a[i]%=313;
    		}
    		memset(d,0,sizeof(d));
    		cdq(1,n);
    		printf("%d
    ",d[n]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    自我介绍
    最大连通子数组求和
    敏捷开发方法综述
    第四周学习进度条
    时间日志和缺陷日志
    最大子数组2.0
    最大子数组1.0
    第三周学习进度条
    小学四则运算3.0
    单元测试
  • 原文地址:https://www.cnblogs.com/WABoss/p/5886232.html
Copyright © 2020-2023  润新知