#8 //HDU 5730 Shell Necklace(CDQ分治+FFT)
Description
给出长度分别为1~n的珠子,长度为i的珠子有a[i]种,每种珠子有无限个,问用这些珠子串成长度为n的链有多少种方案
题解:
- dp[i]表示组合成包含i个贝壳的项链的总方案数
- 转移:dp[i]=Σdp[i-j]*a[j](1<=j<=i)
-
#include <bits/stdc++.h> using namespace std; #define dob complex<double> #define rint register int #define mo 313 #define IL inline const double pi=acos(-1.0); const int N=2e5; dob a[N],b[N],bb[N]; int n,m,r[N],l,dp[N],sum[N]; IL void fft(dob *a,int o) { for (rint i=0;i<n;i++) if (i>r[i]) swap(a[i],a[r[i]]); for (rint i=1;i<n;i*=2) { dob wn(cos(pi/i),sin(pi*o/i)),x,y; for (rint j=0;j<n;j+=(i*2)) { dob w(1,0); for (rint k=0;k<i;k++,w*=wn) { x=a[j+k],y=w*a[i+j+k]; a[j+k]=x+y,a[i+j+k]=x-y; } } } } IL void query() { l=0; for (n=1;n<=m;n<<=1) l++; for (rint i=0;i<n;i++) r[i]=(r[i/2]/2)|((i&1)<<(l-1)); fft(a,1); fft(b,1); for (rint i=0;i<n;i++) a[i]*=b[i]; fft(a,-1); for (rint i=0;i<=m;i++) sum[i]=a[i].real()/n+0.5,sum[i]%=mo; } #define mid (l+r)/2 void cdq(int l,int r) { if (l==r) return; cdq(l,mid); for (rint i=l;i<=mid;i++) a[i-l]=dp[i]; m=r-l; rint x; for (x=1;x<=m;x<<=1); for (rint i=mid+1;i<=l+x;i++) a[i-l]=0; b[0]=0; for (rint i=1;i<=x;i++) b[i]=bb[i]; query(); for (rint i=mid-l+1;i<=r-l;i++) { dp[i+l]+=sum[i]; dp[i+l]%=mo; } cdq(mid+1,r); } int main() { freopen("noi.in","r",stdin); freopen("noi.out","w",stdout); std::ios::sync_with_stdio(false); int k; while (cin>>k&&k) { for (rint i=1;i<=k;i++) cin>>bb[i]; memset(dp,0,sizeof(dp)); dp[0]=1; cdq(0,k); cout<<dp[k]%mo<<endl; } return 0; }
该改一个fft模板了,实在是慢https://www.luogu.org/record/show?rid=3767323