本文做者:ljh2000
做者博客:http://www.cnblogs.com/ljh2000-jump/
轉載請註明出處,侵權必究,保留最終解釋權!php
題目連接:HDU5730ios
正解:分治$FFT$數組
解題報告:spa
分治$+FFT$模板題。blog
容易發現一個$O(n^2)$的$DP$方程,就是一個卷積的形式,在分治過程當中,用左邊更新右邊,作一次$FFT$。get
注意不要每次清空數組就行了。博客
#include <iostream> #include <cstdio> #include <algorithm> #include <queue> #include <complex> #include <cmath> #include <cstring> using namespace std; typedef long long LL; typedef complex<double> C; const int MAXN = 400011; const int mod = 313; const double pi = acos(-1); int n,R[MAXN],L; LL Out[MAXN],tmp[MAXN],a[MAXN]; C c[MAXN],d[MAXN]; inline void FFT(C *a,int n,int f){ for(int i=0;i<n;i++) if(i<R[i]) swap(a[i],a[R[i]]); for(int i=1;i<n;i<<=1) { C wn(cos(pi/i),sin(f*pi/i)),x,t; for(int j=0;j<n;j+=(i<<1)) { C w(1,0); for(int k=0;k<i;k++,w*=wn) { x=a[j+k]; t=a[j+k+i]*w; a[j+k]=x+t; a[j+k+i]=x-t; } } } } inline void calc(LL *aa,int len1,LL *bb,int len2){ int ll=len1+len2; int len=1; L=0; for(;len<=ll;len<<=1) L++; R[0]=0; for(int i=0;i<len;i++) R[i]=(R[i>>1]>>1) | ((i&1) << (L-1)); for(int i=0;i<len1;i++) c[i]=0,c[i]=aa[i]; for(int i=len1;i<=len;i++) c[i]=0; for(int i=0;i<len2;i++) d[i]=0,d[i]=bb[i]; for(int i=len2;i<=len;i++) d[i]=0; FFT(c,len,1); FFT(d,len,1); for(int i=0;i<=len;i++) c[i]*=d[i]; FFT(c,len,-1); for(int i=0;i<=len1+len2;i++) tmp[i]=(LL)(c[i].real()/len+0.5); } inline void fft(int l,int r){ int mid=(l+r)>>1; calc(Out+l,mid-l+1,a,r-l+1); for(int i=mid-l+1;i<=r-l;i++) Out[l+i]+=tmp[i],Out[l+i]%=mod; } inline void CDQ(int l,int r){ if(l==r) return ; int mid=(l+r)>>1; CDQ(l,mid); fft(l,r); CDQ(mid+1,r); } inline void work(){ while(1) { scanf("%d",&n); if(n==0) break; for(int i=1;i<=n;i++) scanf("%lld",&a[i]),a[i]%=mod; memset(Out,0,sizeof(Out)); Out[0]=1; CDQ(0,n); Out[n]+=mod; Out[n]%=mod; printf("%lld\n",Out[n]); } } int main() { work(); return 0; }