題目大意
TN要暗殺Dzx,爲了保密,他想到了這樣一種方式:首先,把信息編碼爲N個實數,組成序列α,之後再隨便搞一個長度爲N的實數序列β。然後按照下面的步驟計算序列γ:
0、做一個空序列γ。
1、把β倒過來。
2、把β向右平移一個元素。最右側的元素補到左邊。
3、計算此時α和β對應元素的積的和。將其加到γ的末尾。
4、如果γ還不足N個元素,重複步驟2和3。
雖然這種加密方法是很弱的,可是那些笨蛋刺客們卻沒法破解。然後,這些東西就被Dzx拿到了,於是他就躲過了暗殺……現在作爲歷史學家的你得到了β和γ,你需要解出α來獲得研究TN的材料。
分析
說得更直白一點, 就是 和 的循環卷積。
運用 所進行的卷積本身就是循環卷積
我們假設 爲 、 兩個序列的卷積,即
令n爲大於等於c的長度而且是2的整數次冪的數,那麼卷積也可以寫成這個形式
FFT就是根據第二個式子算出來的,當 長度相等而且 等於他們的長度的時候,根據這個式子算出來的就是循環卷積。平時計算的時候由於 的長度,所以和線性卷積的式子沒有區別。
很顯然,我們對 和 做 ,然後相除,再 即可,但是用 進行 要求長度必須是2的整數次冪,如果原長不是2的整數次冪,我們強行弄成2的整數次冪的話,在做 的 和最後 時就會出現問題,因爲你根本不知道你這樣做完了是一個什麼東西。
所以,我們需要一個可以做任意長度卷積的東西, 或者混合基 。
Bluestein’s Algorithm
我們考慮 的式子
設
這是一個卷積的形式,我們發現我們可以通過一次卷積來做一次 .
ps:其實是CZT,fft是dft的快速算法,其實就是N點dft算法,就是計算量小一點。N點dft的本質是z變換後,在z域單位圓上等間距N點連續採樣。
的時候,可以類比用 進行 時做出的改變即可。
我們發現 可能小於0,我們只需要將 右移 位即可。
代碼
#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();
}