1. 程式人生 > >Shell Necklace HDU - 5730 [FFT+CDQ分治]

Shell Necklace HDU - 5730 [FFT+CDQ分治]

Shell Necklace HDU - 5730 [FFT+CDQ分治]

Tags: FFT CDQ分治


Shell Necklace HDU - 5730

題意:

S為n的一種分割的形式,表示為一個正整數序列,令S[i]表示序列的第i個元素,那麼滿足下式

i =
1 | S | S [ i ] = n

要求的是
r e s = S i
= 1 | S | S [ i ]

分析:

但是這個樣子並不好?考慮計算貢獻?
但是如果這樣計算貢獻的話就需要乘上之前的東西。
記dp[i]為 已經填了i個的方案總數。
dp[0]=1;

d p [ i ] = j = 0 i 1 d p [ j ] a [ i j ]
看起來很像能隨便優化的樣子。不過每次計算都用到了之前的dp值。所以其實並不能直接用FFT來。
需要求出的只有dp[n]

但是感覺起來就是經典模型啊qwq
難道是快速冪fft?
[不行這樣就連續兩個快速了]

如果知道了 d p [ 0 , l / 2 ] 的話能不能快速求出dp[0,l]呢。
考慮新增貢獻qwq

d p [ i ] = j = l m i d d p [ j ] a [ i j ]
稍微轉化一下
d p [ j + k ] = j = l m i d d p [ j ] a [ k ]
//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;
}