bluestein算法

我们熟知的FFT算法实际上是将一个多项式在2n个单位根处展开,将其点值对应相乘,并进行逆变换。然而,由于单位根具有“旋转”的特征(即$w_{m}^{j}=w_{m}^{j+m}$),若多项式次数大于二分之长度,FFT将进行一次长度为2n的循环卷积。bluestein的算法是解决了在任意长度上的循环卷积问题。

 

我们知道,任何一个n次多项式都可以被n+1个点值进行表示,因此如果我们选取所有形如$w_{n+1}^{i}$的单位根并带入多项式,进行类似于FFT的变化(这里没有证明),理应得到正确的结果。

 

设多项式A为$\sum_{i=0}^{n}{a_i*x^i}$,$F_k$为$A(w_{n+1}^{k})$,则$F_k=\sum_{i=0}^{n}{a_i*w_{n+1}^{ik}}$

 

考虑ik的另外一种组合含义,即有两个盒子,每个盒子分别有i个球和k个球,求有多少种拿出两个球且分别属于两个盒子的方法,因此$ik=\tbinom{i+k}{2}-\tbinom{i}{2}-\tbinom{k}{2}$。它的意义在下面推导中可见。

 

因此$F_k=\sum_{i=0}^{n}{a_i*w_{n+1}^{\tbinom{i+k}{2}-\tbinom{i}{2}-\tbinom{k}{2}}}=w_{n+1}^{-\tbinom{k}{2}}\sum_{i=0}^{n}{a_i*w_{n+1}^{-\tbinom{i}{2}}*w_{n+1}^{\tbinom{i+k}{2}}}$

注意到(i+k)-(i)=k,令$A_{-i}=a_i*w_{n+1}^{-\tbinom{i}{2}}$,$B_i=w_{n+1}^{\tbinom{i}{2}}$。因此,A和B的卷积的第k项即为$F_k$。由于A的下标为负数,我们将A的下标集体加上n。于是,一次bluestein操作花了三次长度为4n的FFT操作。

 

将多项式转化为点值表达后,我们依葫芦画瓢地将对应位置相乘、进行相应的逆变换(即取单位根的共轭)。而此部分正确性的证明过程是与FFT类似的。

 

例题:poj2821

 1 // 2821
 2 #include<cstdio>
 3 #include<math.h>
 4 #include<cstring>
 5 #include<iomanip>
 6 #define mod 998244353
 7 using namespace std;
 8 typedef double ld;
 9 const int maxn=(1<<19)+5;
10 const int LIMIT=1<<19;
11 const ld pi=acos(-1);
12 struct com
13 {
14     ld x,y;
15     com(ld a=0,ld b=0):x(a),y(b){}
16     com operator+(const com&A){return com(x+A.x,y+A.y);}
17     com operator-(const com&A){return com(x-A.x,y-A.y);}
18     com operator*(const com&A){return com(x*A.x-y*A.y,x*A.y+y*A.x);}
19     com operator/(const ld&d){return com(x/d,y/d);}
20     com operator/(const com&A){return com(x,y)*com(A.x,-A.y)/(A.x*A.x+A.y*A.y);}
21     void operator/=(const ld&d){x/=d,y/=d;}
22 };
23 int r[maxn];
24 inline void DFT(com*A,int limit,int type)
25 {
26     for(int i=1;i<limit;++i)
27     {
28         r[i]=(r[i>>1]>>1)|((i&1)?(limit>>1):0);
29         if(i<r[i])
30             swap(A[i],A[r[i]]);
31     }
32     for(int len=2;len<=limit;len<<=1)
33     {
34         com w;
35         if(type==1)
36             w=com(cos(pi*2/len),sin(pi*2/len));
37         else
38             w=com(cos(pi*2/len),-sin(pi*2/len));
39         for(int i=0;i<limit;i+=len)
40         {
41             com d(1,0);
42             for(int j=0,p1=i,p2=i+len/2;j<len/2;++j,++p1,++p2)
43             {
44                 com a=A[p1],b=A[p2]*d;
45                 A[p1]=a+b;
46                 A[p2]=a-b;
47                 d=d*w;
48             }
49         }
50     }
51 }
52 com tmp1[maxn],tmp2[maxn];
53 
54 inline void bluestein(com*A,int n,int type) // n already stands for the number of terms
55 {
56     int limit=1;
57     while(limit<4*n) // 4 times !!!!!!!
58         limit<<=1;
59     for(int i=0;i<limit;++i)
60         tmp1[i]=tmp2[i]=0;
61     for(int i=0;i<n;++i)
62         tmp1[i]=A[i]*com(cos(pi*i*i/n),type*sin(pi*i*i/n));
63     for(int i=0;i<n*2;++i)
64         tmp2[i]=com(cos(pi*(i-n)*(i-n)/n),-type*sin(pi*(i-n)*(i-n)/n));
65     DFT(tmp1,limit,1);
66     DFT(tmp2,limit,1);
67     for(int i=0;i<limit;++i)
68         tmp1[i]=tmp1[i]*tmp2[i];
69     DFT(tmp1,limit,-1);
70     for(int i=0;i<n;++i)
71         A[i]=tmp1[i+n]*com(cos(pi*i*i/n),type*sin(pi*i*i/n))/limit; // dont forget this !!!
72 }
73 com A[maxn],B[maxn],C[maxn];
74 int n;
75 int main()
76 {
77     scanf("%d",&n);
78     --n;
79     for(int i=0;i<=n;++i)
80         scanf("%lf",&A[i].x);
81     for(int i=0;i<=n;++i)
82         scanf("%lf",&B[i].x);
83     bluestein(A,n+1,1);
84     bluestein(B,n+1,1);
85     for(int i=0;i<n+1;++i)
86         A[i]=B[i]/A[i];
87     bluestein(A,n+1,-1);
88     for(int i=0;i<=n;++i)
89         A[i].x/=(n+1);
90     for(int i=0;i<=n;++i)
91         printf("%.4f\n",A[i].x);
92     return 0;
93 }

View Code

 

Tags: