Shell Necklace HDU - 5730 [FFT+CDQ分治]
阿新 • • 發佈:2018-12-24
Shell Necklace HDU - 5730 [FFT+CDQ分治]
Tags: FFT CDQ分治
Shell Necklace HDU - 5730
題意:
S為n的一種分割的形式,表示為一個正整數序列,令S[i]表示序列的第i個元素,那麼滿足下式
要求的是
分析:
但是這個樣子並不好?考慮計算貢獻?
但是如果這樣計算貢獻的話就需要乘上之前的東西。
記dp[i]為 已經填了i個的方案總數。
dp[0]=1;
看起來很像能隨便優化的樣子。不過每次計算都用到了之前的dp值。所以其實並不能直接用FFT來。
需要求出的只有dp[n]
但是感覺起來就是經典模型啊qwq
難道是快速冪fft?
[不行這樣就連續兩個快速了]
如果知道了
的話能不能快速求出dp[0,l]呢。
考慮新增貢獻qwq
稍微轉化一下
//2018年06月15日 星期五 21時25分54秒
簡單來說就是用CDQ分治來實現dp從小到大逐個更新的效果。
code
//2018年06月15日 星期五 21時25分54秒
#include<bits/stdc++.h>
#define M 200005
#define ll long long
#define mo 313
#define db long double
using namespace std;
void read(int &x){
x=0; char c=getchar();
for (;c<48;c=getchar());
for (;c>47;c=getchar())x=(x<<1)+(x<<3)+(c^48);
}
struct Complex{
db r,i;
Complex(db R=0,db I=0){
r=R; i=I;
}
};
Complex operator +(const Complex &x,const Complex &y){
return Complex(x.r+y.r,x.i+y.i);
}
Complex operator -(const Complex &x,const Complex &y){
return Complex(x.r-y.r,x.i-y.i);
}
Complex operator *(const Complex &x,const Complex &y){
return Complex(x.r*y.r-x.i*y.i,x.r*y.i+x.i*y.r);
}
Complex operator /(const Complex &x,const int &y){
return Complex(x.r/y,x.i/y);
}
const db pi=acos(-1.0);
int rev[M<<2];
struct FFT{
Complex a[M<<2];
Complex &operator[](int i){
return a[i];
}
void clear(int n){
int i;
for (i=0;i<n;i++)a[i]=Complex(0,0);
}
void solve(int n,int DFT){
register int i,j,k,m;
Complex w,wn,l,r;
for (i=0;i<n;i++)if (rev[i]<i)swap(a[rev[i]],a[i]);
for (m=1;m<n;m<<=1){
k=m<<1;
w=Complex(1,0);
wn=Complex(cos(pi*DFT/m),sin(pi*DFT/m));
for (i=0;i<m;i++){
for (j=i;j<n;j+=k){
l=a[j];
r=a[j+m];
a[j]=l+r*w;
a[j+m]=l-r*w;
}
w=w*wn;
}
}
if (DFT==-1){
for (i=0;i<n;i++)a[i]=a[i]/n;
}
}
}A,B;
int k,dp[M],a[M];
void solve(int l,int r){
if (l==r){
return ;
}
int mid=(l+r)>>1,i;
solve(l,mid);
int len=r-l+1;
for (k=1;k<=len;k<<=1);
for (i=0;i<k;i++)rev[i]=(rev[i>>1]>>1)|((i&1)*(k>>1));
A.clear(k); B.clear(k);
for (i=l;i<=mid;i++){
A[i-l]=Complex(dp[i],0);
}
for (i=1;i<len;i++){
B[i]=Complex(a[i],0);
}
A.solve(k,1); B.solve(k,1);
for (i=0;i<k;i++)A[i]=A[i]*B[i];
A.solve(k,-1);
for (i=mid+1;i<=r;i++){
dp[i]=(dp[i]+(ll)(A[i-l].r+0.5))%mo;
}
solve(mid+1,r);
}
int main(){
// freopen("1.in","r",stdin);
int n,i;
for (read(n);n;read(n)){
for (i=1;i<=n;i++)read(dp[i]),a[i]=dp[i];
solve(1,n);
printf("%d\n",(dp[n]%mo+mo)%mo);
}
return 0;
}