我们熟知的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. Kali-2020 配置Docker

    Kali 2020 安装Docke 为什么在Kali上安装Docker? Kali有很多工具,但是您想运行一个不包含的工具,最干净的方法是通过Docker容器.例如,我正在研究一个名为vulhub的靶 ...

  2. Mac通过docker一键部署airflow

    目录 Airflow部署及使用 1.Dockerhub查看镜像地址 2.拉取docker镜像 3.在宿主机创建外挂文件夹 4.创建docker容器 5.重新创建docker容器 5.1.查看airfl ...

  3. 2013 Asia Hangzhou Regional Contest hdu4780 Candy Factory

    参考:https://blog.csdn.net/sd_invol/article/details/15813671 要点 每个任务的结束时间是固定的,不受任何因素影响 机器只在最一开始有用,在那之后 ...

  4. Educational Codeforces Round 91 (Rated for Div. 2) D. Berserk And Fireball

    题目链接:https://codeforces.com/contest/1380/problem/D 题意 给出一个大小为 $n$ 的排列 $a$ 和一个序列 $b$,有两种操作: 花费 $x$ 消除 ...

  5. 最短Hamilton路径(状压dp)

    最短Hamilton路径实际上就是状压dp,而且这是一道作为一个初学状压dp的我应该必做的题目 题目描述 给定一张 n(n≤20) 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 ...

  6. GPTL L3-003 社交集群(并查集)

    数据有些弱,Union函数不判不等也可以过. 题意: 依次给出 n 个人的兴趣,不同人兴趣相交.不同兴趣所属人员相交均属于同一集群,求形成的不相交集群个数及每个集群的人数. 思路: 枚举每个兴趣的人员 ...

  7. Codeforces Round #647 (Div. 2) A. Johnny and Ancient Computer

    题目链接:https://codeforces.com/contest/1362/problem/A 题意 有一个正整数 $a$,可选择的操作如下: $a \times 2$ $a \times 4$ ...

  8. [IOI1998] Polygon (区间dp,和石子合并很相似)

    题意: 给你一个多边形(可以看作n个顶点,n-1条边的图),每一条边上有一个符号(+号或者*号),这个多边形有n个顶点,每一个顶点有一个值 最初你可以把一条边删除掉,这个时候这就是一个n个顶点,n-2 ...

  9. 实战交付一套dubbo微服务到k8s集群(1)之Zookeeper部署

    基础架构 主机名 角色 IP地址 mfyxw10.mfyxw.com K8S代理节点1,zk1 192.168.80.10 mfyxw20.mfyxw.com K8S代理节点2,zk2 192.168 ...

  10. MySQL 索引的类型

    主键索引(PRIMARY KEY) # 主键 = 唯一键索引 + 非空 + 只能设置一个字段 # 创建表的时候创建主键索引 mysql> create table test(id int not ...