【Bluestein's Algorithm】[POJ2821]TN's Kingdom III - Assassination

題目大意

TN要暗殺Dzx,爲了保密,他想到了這樣一種方式:首先,把信息編碼爲N個實數,組成序列α,之後再隨便搞一個長度爲N的實數序列β。然後按照下面的步驟計算序列γ:
0、做一個空序列γ。
1、把β倒過來。
2、把β向右平移一個元素。最右側的元素補到左邊。
3、計算此時α和β對應元素的積的和。將其加到γ的末尾。
4、如果γ還不足N個元素,重複步驟2和3。

雖然這種加密方法是很弱的,可是那些笨蛋刺客們卻沒法破解。然後,這些東西就被Dzx拿到了,於是他就躲過了暗殺……現在作爲歷史學家的你得到了β和γ,你需要解出α來獲得研究TN的材料。

分析

說得更直白一點,γ 就是αβ 的循環卷積。

運用FFT 所進行的卷積本身就是循環卷積

我們假設cab 兩個序列的卷積,即ck=i=0kak×bki
令n爲大於等於c的長度而且是2的整數次冪的數,那麼卷積也可以寫成這個形式ck=i,jakbj[i+j0(modn)]
FFT就是根據第二個式子算出來的,當a,b 長度相等而且n 等於他們的長度的時候,根據這個式子算出來的就是循環卷積。平時計算的時候由於nc 的長度,所以和線性卷積的式子沒有區別。
很顯然,我們對γβDFT ,然後相除,再IDFT 即可,但是用FFT 進行DFT 要求長度必須是2的整數次冪,如果原長不是2的整數次冪,我們強行弄成2的整數次冪的話,在做γDFT 和最後IDFT 時就會出現問題,因爲你根本不知道你這樣做完了是一個什麼東西。
所以,我們需要一個可以做任意長度卷積的東西,Bluesteins  Algorithm 或者混合基FFT

Bluestein’s Algorithm

我們考慮DFT 的式子

(11)Ak=j=0N1ajωNjk(12)=j=0N1aje2πiNjk(13)jk=(jk)2+j2+k22(14)Ak=j=0N1ajeπiN((jk)2+j2+k2)(15)=eπiNk2ajeπiNj2eπiN((kj)2)

Xj=ajeπiNj2,Yj=eπiNj2

Ak=eπiNk2j=0NXjYkj

這是一個卷積的形式,我們發現我們可以通過一次卷積來做一次DFT .
ps:其實是CZT,fft是dft的快速算法,其實就是N點dft算法,就是計算量小一點。N點dft的本質是z變換後,在z域單位圓上等間距N點連續採樣。
IDFT 的時候,可以類比用FFT 進行IDFT 時做出的改變即可。
我們發現kj 可能小於0,我們只需要將Y(x) 右移N 位即可。

代碼

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const double pi=acos(-1);
#define MAXN (1<<17)
int n;
struct cpx{
    double r,i;
    inline cpx(){
    }
    inline cpx(double r,double i=0):r(r),i(i){
    }
    inline cpx operator+(const cpx &b)const{
        return cpx(r+b.r,i+b.i);
    }
    inline cpx operator-(const cpx &b)const{
        return cpx(r-b.r,i-b.i);
    }
    inline cpx operator*(const cpx &b)const{
        return cpx(r*b.r-i*b.i,r*b.i+i*b.r);
    }
    inline cpx operator/(const cpx &b)const{
        return cpx((r*b.r+i*b.i)/(b.r*b.r+b.i*b.i),(i*b.r-r*b.i)/(b.r*b.r+b.i*b.i));
    }
    inline cpx& operator*=(const cpx &b){
        return *this=*this*b;
    }
    inline cpx &operator/=(const cpx &b){
        return *this=*this/b;
    }
}beta [MAXN+10],gamma[MAXN+10],alpha[MAXN+10],A[MAXN*4+10],B[MAXN*4+10];
void fft(cpx *a,int N,int f){
    int i,j,t,k;
    for(i=1,j=0;i<N-1;i++){
        for(t=N;j^=(t>>=1),~j&t;);
        if(i<j)
            swap(a[i],a[j]);
    }
    for(i=1;i<N;i<<=1){
        cpx wn(cos(pi/i),f*sin(pi/i));
        t=i<<1;
        for(j=0;j<N;j+=t){
            cpx w(1,0);
            for(k=0;k<i;k++,w*=wn){
                cpx x(a[j+k]),y(w*a[j+i+k]);
                a[j+k]=x+y;
                a[j+i+k]=x-y;
            }
        }
    }
    if(f==-1){
        for(i=0;i<N;i++)
            a[i]/=N;
    }
}
void bluestein(cpx *a,int n,int f){
    int N,i;
    memset(A,0,sizeof A);
    memset(B,0,sizeof B);
    for(i=0;i<n;i++)
        A[i]=cpx(cos(pi*i*i/n),f*sin(pi*i*i/n))*a[i];
    for(i=0;i<(n<<1);i++)
        B[i]=cpx(cos(pi*(i-n)*(i-n)/n),-f*sin(pi*(i-n)*(i-n)/n));
    for(N=1;N<(n<<2);N<<=1);
    fft(A,N,1);
    fft(B,N,1);
    for(i=0;i<N;i++)
        A[i]*=B[i];
    fft(A,N,-1);
    for(i=0;i<n;i++){
        a[i]=A[i+n]*cpx(cos(pi*i*i/n),f*sin(pi*i*i/n));
        if(f==-1)
            a[i]/=n;
    }
}
void read(){
    scanf("%d",&n);
    int i;
    for(i=0;i<n;i++)
        scanf("%lf",&beta[i].r);
    for(i=0;i<n;i++)
        scanf("%lf",&gamma[i].r);
}
void solve(){
    bluestein(beta,n,1);
    bluestein(gamma,n,1);
    for(int i=0;i<n;i++)
        alpha[i]=gamma[i]/beta[i];
    bluestein(alpha,n,-1);
}
void print(){
    int i;
    for(i=0;i<n;i++)
        printf("%.4f\n",alpha[i].r);
}
int main()
{
    read();
    solve();
    print();
}
發佈了171 篇原創文章 · 獲贊 64 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章