我们熟知的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 }

bluestein算法的更多相关文章

  1. 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT)

    再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT) 目录 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Blueste ...

  2. [POJ 2821]TN's Kindom III(任意长度循环卷积的Bluestein算法)

    [POJ 2821]TN's Kindom III(任意长度循环卷积的Bluestein算法) 题面 给出两个长度为\(n\)的序列\(B,C\),已知\(A\)和\(B\)的循环卷积为\(C\),求 ...

  3. 算法系列:FFT 002

    转载自http://blog.jobbole.com/58246/ 快速傅里叶变换(Fast Fourier Transform)是信号处理与数据分析领域里最重要的算法之一.没有正规计算机科学课程背景 ...

  4. 快速傅里叶变换(FFT)算法【详解】

    快速傅里叶变换(Fast Fourier Transform)是信号处理与数据分析领域里最重要的算法之一.我打开一本老旧的算法书,欣赏了JW Cooley 和 John Tukey 在1965年的文章 ...

  5. B树——算法导论(25)

    B树 1. 简介 在之前我们学习了红黑树,今天再学习一种树--B树.它与红黑树有许多类似的地方,比如都是平衡搜索树,但它们在功能和结构上却有较大的差别. 从功能上看,B树是为磁盘或其他存储设备设计的, ...

  6. 分布式系列文章——Paxos算法原理与推导

    Paxos算法在分布式领域具有非常重要的地位.但是Paxos算法有两个比较明显的缺点:1.难以理解 2.工程实现更难. 网上有很多讲解Paxos算法的文章,但是质量参差不齐.看了很多关于Paxos的资 ...

  7. 【Machine Learning】KNN算法虹膜图片识别

    K-近邻算法虹膜图片识别实战 作者:白宁超 2017年1月3日18:26:33 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本系列文章是作者结 ...

  8. 红黑树——算法导论(15)

    1. 什么是红黑树 (1) 简介     上一篇我们介绍了基本动态集合操作时间复杂度均为O(h)的二叉搜索树.但遗憾的是,只有当二叉搜索树高度较低时,这些集合操作才会较快:即当树的高度较高(甚至一种极 ...

  9. 散列表(hash table)——算法导论(13)

    1. 引言 许多应用都需要动态集合结构,它至少需要支持Insert,search和delete字典操作.散列表(hash table)是实现字典操作的一种有效的数据结构. 2. 直接寻址表 在介绍散列 ...

随机推荐

  1. Spring Cloud与Eureka

    Spring Cloud与Eureka 一.使用SpringCloud注册中心Eureka 1.1 Eureka和Zookeeper对比 1.1.1 Zookeeper保证CP 1.1.2 Eurek ...

  2. python模块----paramicko模块 (ssh远程主机并命令或传文件)

    paramiko模块 paramicko模块是非标准库模块,需要pip下载 paramicko:模拟ssh登陆linux主机,也有上传下载功能.ansible自动化部署软件底层就有应用paramick ...

  3. Effective Java读书笔记--类和接口

    1.使类和成员的可访问性最小化不指定访问级别,就是包私有.protected = 包私有 + 子类一般private不会被访问到,如果实现了Serializable,可能会泄露.反射.final集合或 ...

  4. MySQL复合索引探究

    复合索引(又称为联合索引),是在多个列上创建的索引.创建复合索引最重要的是列顺序的选择,这关系到索引能否使用上,或者影响多少个谓词条件能使用上索引.复合索引的使用遵循最左匹配原则,只有索引左边的列匹配 ...

  5. shell脚本的使用该熟练起来了,你说呢?(篇二)

    继续前一篇的文章: shell脚本的使用该熟练起来了,你说呢?(篇一) 作者:良知犹存 转载授权以及围观:欢迎添加微信公众号:羽林君 shell传递参数 shell传递参数 我们可以在执行 Shell ...

  6. Codeforces Round #640 (Div. 4)

    比赛链接:https://codeforces.com/contest/1352 A - Sum of Round Numbers 题意 将一个十进制数的每一个非零位分离出来. 代码 #include ...

  7. A. Little Pony and Expected Maximum

    Twilight Sparkle was playing Ludo with her friends Rainbow Dash, Apple Jack and Flutter Shy. But she ...

  8. hdu5564 Clarke and digits

    Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission ...

  9. HDU-3081-Marriage Match II 二分图匹配+并查集 OR 二分+最大流

    二分+最大流: 1 //题目大意:有编号为1~n的女生和1~n的男生配对 2 // 3 //首先输入m组,a,b表示编号为a的女生没有和编号为b的男生吵过架 4 // 5 //然后输入f组,c,d表示 ...

  10. hdu5360 Hiking

    Problem Description There are n soda conveniently labeled by 1,2,-,n. beta, their best friends, want ...