快速傅里叶变换总结

news/2025/1/17 20:23:24/文章来源:https://www.cnblogs.com/vanueber/p/18677622

基本概念

对于求和式 \(\sum a_ix^i\),如果是有限项相加,称为多项式,记作

\[f(x)=\sum_{i=0}^n a_ix^i。 \]

其中最高次项的次数为 \(n\),为 \(n\) 次多项式。

\(n+1\) 个点可以唯一地确定一个 \(n\) 次多项式,这一过程可以参考 拉格朗日插值。

引入

给定多项式 \(f(x),g(x)\),求 \(f(x)\cdot g(x)\)各项系数。

通过系数表达式直接乘时间复杂度 \(\Theta(n^2)\),但考虑两个函数的一组点值表达式

\[(x_1,f(x_1))\cdots(x_k,f(x_k))\\ (x_1,g(x_1))\cdots(x_k,g(x_k)) \]

此时两者相乘的点值表达式可以在 \(\Theta(n)\) 的时间求出。

即:

\[(x_1,f(x_1)\cdot g(x_1))\cdots(x_k,f(x_k)\cdot g(x_k)) \]

于是就有想法:将系数表达式 \(\Rightarrow\) 点值表达式,点值相乘后 \(\Rightarrow\) 系数表达式。

快速傅里叶变换就是完成中间过程的工具,可以在 \(\Theta(n \log n)\) 的时间完成系数表示与点值表示的转换。

前置知识

复数

有以下重要知识

欧拉公式:

\[\mathrm{e}^{\mathrm{i}x}=\cos x+\mathrm{i}\sin x \]

单位复数根:

\[\begin{aligned} \omega_n^k&= \cos \frac{2 \pi k}{n} + \mathrm{i} \sin \frac{2 \pi k}{n} \\ \omega_n^n&=1\\ \omega_n^k&=\omega_{2n}^{2k}\\ \omega_{2n}^{k+n}&=-\omega_{2n}^k\\ \end{aligned} \]

快速傅里叶变换

将多项式 \(f(x)=\sum_{i=0}^{n}a_ix^i\) 按照下标为奇偶数划分为两个多项式

\[G(x)=a_0+a_2{x^1}+a_4{x^2}+\dots+a_{n-2}x^{\frac{n}{2}-1}\\ H(x)=a_1+a_3{x}+a_5{x^2}+ \dots+a_{n-1}x^{\frac{n}{2}-1}\]

有:

\[f(x)= G(x^2) + xH(x^2) \]

代入两组值:
得到:

\[\begin{aligned} f(\omega_n^k) &= G((\omega_n^k)^2) + \omega_n^k \times H((\omega_n^k)^2) \\&= G(\omega_n^{2k}) + \omega_n^k \times H(\omega_n^{2k}) \\&= G(\omega_{n/2}^k) + \omega_n^k \times H(\omega_{n/2}^k) \end{aligned}\\ \begin{aligned} f(\omega_n^{k+n/2}) &= G(\omega_n^{2k+n}) + \omega_n^{k+n/2} \times H(\omega_n^{2k+n}) \\&= G(\omega_n^{2k}) - \omega_n^k \times H(\omega_n^{2k}) \\&= G(\omega_{n/2}^k) - \omega_n^k \times H(\omega_{n/2}^k) \end{aligned} \]

发现只要求出 \(G(\omega_n^{2k}),H(\omega_{n/2}^k)\) 的值就可以同时求得 \(f(\omega_n^k),f(\omega_n^{k+n/2})\) 的值。

并且这个问题跟原问题是相同的。

于是分治下来解决子问题,最后合并为原问题即可。

void FFT(comp f[],int n)
{if(n==1) return;comp f1[n/2],f2[n/2];for(int i=0;i<n/2;++i){f1[i]=f[i<<1],f2[i]=f[i<<1|1];}FFT(f1,n/2),FFT(f2,n/2);comp w=polar(1.0,(2.0*pi/n)),wk=comp(1,0);for(int i=0;i<n/2;++i){f[i]=f1[i]+f2[i]*wk;f[i+n/2]=f1[i]-f2[i]*wk;wk*=w;}
}

快速傅里叶逆变换

现在完成了系数表示法 \(\Rightarrow\) 点值表示法的过程,现在考虑逆向转换。

有结论:

IFFT等价于 FFT 中代入得复数变为其倒数,再除以变换长度。

证明

故结论成立。

容易证明,这也等价于将\(\{y_0,y_1,y_2,\cdots,y_{n-1}\}\) 做 FFT 变换后除以 \(n\),再反转后 \(n - 1\) 个元素。

优化

以上的代码实现都基于递归,常数较大。

基于以下观察,可以写出迭代写法。

1

原位置对应元素的下表二进制翻转后,成了最后当前元素的下标,于是这样处理之后直接自底向上合并即可。

代码

递归版本

#include <bits/stdc++.h>using namespace std;const int INF=0x3f3f3f3f;
inline int read()
{int w=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){w=(w<<1)+(w<<3)+(ch^48);ch=getchar();}return w*f;
}
inline void write(int x)
{if(x<0){putchar('-');x=-x;}if(x>9) write(x/10);putchar(x%10+'0');
}
#define comp complex<double>
const int maxn=2e6+10;
const double pi=3.1415926535;
void FFT(comp f[],int n)
{if(n==1) return;comp f1[n/2],f2[n/2];for(int i=0;i<n/2;++i){f1[i]=f[i<<1],f2[i]=f[i<<1|1];}FFT(f1,n/2),FFT(f2,n/2);comp w=polar(1.0,(2.0*pi/n)),wk=comp(1,0);// comp w=comp(cos(2.0*pi/n),type*sin(2.0*pi/n)),wk=comp(1,0);for(int i=0;i<n/2;++i){f[i]=f1[i]+f2[i]*wk;f[i+n/2]=f1[i]-f2[i]*wk;wk*=w;}
}
void IFFT(comp f[],int n)
{FFT(f,n);reverse(f+1,f+n);
}
int n,m;
comp a[maxn<<1],b[maxn<<1];int main()
{#ifndef ONLINE_JUDGE//freopen("in.txt","r",stdin);#endifn=read(),m=read();for(int i=0;i<=n;++i) a[i]=comp(read(),0);for(int i=0;i<=m;++i) b[i]=comp(read(),0);int k=1;while(k<=n+m) k<<=1;// cout<<k<<endl;FFT(a,k),FFT(b,k);for(int i=0;i<=k;++i){a[i]*=b[i];}IFFT(a,k);for(int i=0;i<=n+m;++i){cout<<(int)(a[i].real()/k+0.5)<<" ";}return 0;
}

迭代版本

#include <bits/stdc++.h>using namespace std;inline int read()
{int w=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){w=(w<<1)+(w<<3)+(ch^48);ch=getchar();}return w*f;
}
void write(int x)
{if(x<0) x=-x;if(x>9) write(x/10);putchar(x%10+'0');
}
#define comp complex<double>const double pi=acos(-1);
const int maxn=4e6+10;
int n,m,len,k;
int rev[maxn];
comp a[maxn],b[maxn];int get(int x)
{int res=0;for(int i=0;i<len;++i){res+=(x>>i&1)<<(len-i-1);}return res;
}
void fft(comp f[],int n)
{for(int i=0;i<n;++i){rev[i]=get(i);if(i<rev[i]) swap(f[i],f[rev[i]]);}for(int h=2;h<=n;h<<=1){comp w=polar(1.0,2.0*pi/h);for(int i=0;i<n;i+=h){comp wk=comp(1,0);for(int j=0;j<h/2;++j){comp x=f[i+j],y=f[i+j+h/2]*wk;f[i+j]=x+y,f[i+j+h/2]=x-y;wk*=w;}}}
}
void ifft(comp f[],int n)
{fft(f,n);reverse(f+1,f+n);
}int main()
{n=read(),m=read();for(int i=0;i<=n;++i) a[i]=read();for(int i=0;i<=m;++i) b[i]=read();k=1;while(k<=n+m) k<<=1,++len;fft(a,k),fft(b,k);for(int i=0;i<=k;++i) a[i]*=b[i];ifft(a,k);for(int i=0;i<=n+m;++i) printf("%d ",(int)(a[i].real()/k+0.5));return 0;
}

解释:蝶形变换的位置数组有 \(\Theta(n)\) 的解法,但考虑 FFT 的瓶颈不在此,暴力的写法也是可行的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/870939.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

寒假学习1

老年人评估系统 初步整理web端思路先写了第一张信息表并搭建基本框架并编写了老年人信息添加功能

1.17安卓测试

今天在idea进行安卓虚拟机测试成功,昨天的错误是因为版本不兼容 启动虚拟机运行测试

【Azure APIM】升级中国区APIM服务 stv1 到 stv2 遇见错误

Invalid parameter: This Migration API option is not supported or is temporarily disabled due to internal issues. Please visit https://aka.ms/apim-migrate-stv2 to see other migration options.问题描述 在执行Azure API Management服务升级的操作中 (从 stv1 升级到…

高频面题: 你们线上 QPS 多少?你 怎么知道的?

本文原文链接 文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 : 免费赠送 :《尼恩Java面试宝典》 持续更新+ 史上最全 + 面试必备 2000页+ 面试必备 + 大厂必备 +涨薪必备 免费赠送 :《尼恩技术圣经+高并发系列PDF》 ,帮你 …

【Java安全】CB链详细分析

免责申明: 本公众号所分享内容仅用于网络安全技术讨论,切勿用于违法途径,所有渗透都需获取授权,违者后果自行承担,与本号及作者无关,请谨记守法.环境配置 pom.xml添加: <dependency> <groupId>commons-beanutils</groupId> <artifactId>commo…

17-php相关知识

1、安装最新版phpstudy集成工具并创建一个网站,编写php代码输出网站信息(phpinfo)利用小皮创建一个名叫pikachu的网站,根目录为pikachu源码存放的目录在根目录下的test目录中创建info.php文件(内容为<?php phpinfo;?>)浏览器访问该地址,输出pikachu网站对应的ph…

ljnljn的春秋杯冬季赛wp(1.17)

杂项 1、See anything in these pics? 压缩包里有个码,确认是aztec码这个是压缩包密码,解压出一张图片 binwalk找到多个图片,foremost分离 1:JPEG image data, JFIF standard 1.01 2:PNG image, 360 x 450, 8-bit grayscale, non-interlaced 3:TIFF image data, big-endian…

金融行业构建高效知识库:策略与实践

在金融行业,信息的准确性和时效性至关重要。随着业务范围的扩大和产品线的丰富,金融机构面临着前所未有的知识管理挑战。一个高效、易用的内部知识库不仅能够提升员工工作效率,还能增强客户服务质量,促进业务创新。本文将提供一套快速搭建金融行业内部知识库的指南,并简要…

智慧医疗的知识库:赋能医疗创新与患者服务

智慧医疗的发展正深刻改变着医疗行业的面貌,从精准医疗到远程诊疗,从健康管理到疾病预防,技术的革新带来了前所未有的机遇。然而,随着医疗数据的爆炸式增长和医疗知识的不断更新,如何高效管理并利用这些知识成为智慧医疗发展的关键。本文将对智慧医疗内部知识库进行深入剖…

如何对需求分析进行测试(阅读《有效需求分析》触发的思考)

我的初步理解 1. 明确满意条件定义任务的满意条件(验收条件),确保开发目标清晰可衡量。2. 提供Checklist制定Checklist,明确必填项和关键检查点,确保任务完成的完整性和一致性。3. 需求与特性的关联需求归属:明确当前用户需求属于哪个特性(Feature),并了解该特性下的其…

在绩效管理中采用OKR的优势

现代的绩效管理体系剔除旧的年度绩效管理系统,以获取此现代系统的好处,该系统可基于连续的反馈进行频繁的绩效评估系统。 OKR绝对清晰地说明了需要优先考虑的事项以及如何帮助公司取得成功。 透明度和与组织目标的一致性可确保员工符合组织目标,并更有动力和参与度基于OKR的…

2025高级java面试精华及复习方向总结

1. Java基础 顶顶顶顶的点点滴滴 1.1 java集合关系结构图 1.2 如何保证ArrayList的线程安全 方法一: 使用 Collections 工具类中的 synchronizedList 方法List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>()); 使用锁机制 …