HDU 5730 Shell Necklace cdq分治+FFT

题意:一段长为 i 的项链有 a[i] 种装饰方式,问长度为n的相连共有多少种装饰方式

分析:采用dp做法,dp[i]=∑dp[j]*a[i-j]+a[i],(1<=j<=i-1)

然后对于这种递推式,也就是dp[i]等于前j个dp数组和a数组的卷积,然后可看所有的

一看n是1e5,所以暴力超时,然后采用cdq分治加速,这种卷积递推通常采用cdq分治加速

 cdq的话很简单了,就是先递归左边,算左对右的贡献,递归右边就行,一半一半更新

#include <cstdio>
#include <vector>
#include <stack>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5+5;
const int mod = 313;
typedef long long LL;
const double pi = acos(-1.0);
int a[N],dp[N],n;
struct complex{
  double r,i;
  complex(double R=0,double I=0){
    r=R;i=I;
  }
  complex operator+(const complex &a)const{
    return complex(r+a.r,i+a.i);
  }
  complex operator-(const complex &a)const{
    return complex(r-a.r,i-a.i);
  }
  complex operator*(const complex &a)const{
    return complex(r*a.r-i*a.i,r*a.i+i*a.r);
  }
}x[N*4],y[N*4];
void change(complex x[],int len){
   int i,j,k;
   for(i=1,j=len/2;i<len-1;++i){
     if(i<j)swap(x[i],x[j]);
     k=len/2;
     while(j>=k){j-=k;k>>=1;}
     if(j<k)j+=k;
   }
}
void fft(complex x[],int len,int on){
   change(x,len);
   for(int i=2;i<=len;i<<=1){
    complex wn(cos(-on*2*pi/i),sin(-on*2*pi/i));
    for(int j=0;j<len;j+=i){
      complex w(1,0);
      for(int k=j;k<j+i/2;++k){
          complex u = x[k];
          complex t = w*x[k+i/2];
          x[k]=u+t;
          x[k+i/2]=u-t;
          w=w*wn;
      }
    }
   }
   if(on==-1)for(int i=0;i<len;++i)x[i].r/=len;
}
void up(int &x){
  x%=mod;
}
void cdq(int l,int r){
  if(l==r){dp[l]+=a[l];up(dp[l]);return;}
  int mid=l+r>>1;
  cdq(l,mid);
  int len=1;
  while(len<=(r-l+1))len<<=1;
  for(int i=0;i<len;++i)x[i]=y[i]=complex(0,0);
  for(int i=l;i<=mid;++i)x[i-l]=complex(dp[i],0);
  for(int i=1;i<=r-l+1;++i)y[i-1]=complex(a[i],0);
  fft(x,len,1);fft(y,len,1);
  for(int i=0;i<len;++i)x[i]=x[i]*y[i];
  fft(x,len,-1);
  for(int i=mid+1;i<=r;++i)
    dp[i]+=(int)(x[i-l-1].r+0.5),up(dp[i]);
  cdq(mid+1,r);
}
int main(){
    while(~scanf("%d",&n),n){
       for(int i=1;i<=n;++i){
        scanf("%d",&a[i]);up(a[i]);dp[i]=0;
       }
       cdq(1,n);
       printf("%d\n",dp[n]);
    }
    return 0;
}
View Code

 

posted @ 2016-07-25 22:09  shuguangzw  阅读(256)  评论(0编辑  收藏  举报