FFT(快速傅里叶变换)
学习了FFT用来求多项式的乘法,看了算导上的介绍,上面讲的非常明白,概括一下FFT的原理就是,我们在计算多项式的乘法时,如果暴力模拟的话是n^2 复杂度的,就像小学学的竖式乘法一样,比如一个n位数乘上一个n位数,我们需要用竖式乘法计算要列n行,每一行有n个元素,然后相邻两行错开一位(很显然,竖式乘法谁都会),如果我们换一种形式呢?有一种表达是叫做点值表达,就好像我们上了初中学二次函数,如果已知函数图像上的三个不同的点坐标,我们可以写出函数的表达式,那么就是说利用函数图象上的点我们也可以确定一个函数(多项式),这样的好处在于点值表达式更加容易进行乘法运算,举个例子:
我们现在有两个函数: y1=2*x*x+5*x+1 y2=x*x+2*x+1 我们要求y1*y2的表达式。如果利用系数表达,我们利用竖式乘法可以手算出答案,复杂度n^2.
由于两个函数是二次的,乘起来是四次的,所以我们需要知道5个点的坐标。
x | 1 | 2 | 3 | 4 | 5 |
y1 | 8 | 19 | 34 | 53 | 76 |
y2 | 4 | 9 | 16 | 25 | 36 |
y | 32 | 171 | 544 | 1325 | 2736 |
我们现在已知了y的五个坐标,那么肯定可以求出y的表达式,那么多项式乘法也就做完了。
可以看出对于点值表达,它的乘法操作是O(N)的,只需要把对应的y值乘起来即可。
那么FFT算法就诞生了,他就是利用点值表达的优点,把系数表达转换成点值表达,然后再转化回去。
从系数表达到点值表达的过程交做求值,利用秦九韶公式我们可以O(N)的算出一个点对应的y值。
从点值表达到系数表达的过程叫做差值,著名的拉格朗日插值法复杂度是O(N^2)的,这对于我们多项式乘法没有太大帮助。
因为差值对于我们取哪些点并没有要求,所以我们选取一些特殊点,利用一些特殊性质可以优化插值的过程。
利用了复数根的知识,大概原理就是,我们可以分治的求一个系数向量,每一次递归求一半,然后可以O(N)的合并,在算导的第三十章都有讲到,推荐大家去看算导,里面讲的非常详细易懂。由于我太菜了,讲不清其中的奥秘。
所以只能在这里给出程序代码了,我没有进行递归的求解,进行了迭代操作,看一下算导上30-4的图就明白r数组的含义了,其实就是计算的顺序。 —— by VANE
#include<bits/stdc++.h>
#define N 3000005
#define pi acos(-1)
using namespace std;
typedef complex<double> E;
int n,m,l,r[N];
E a[N],b[N];
void FFT(E *a,int f){
for(int i=;i<n;i++)if(i<r[i])swap(a[i],a[r[i]]);
for(int i=;i<n;i<<=)
{
E wn(cos(pi/i),f*sin(pi/i));
for(int p=i<<,j=;j<n;j+=p)
{
E w(,);
for(int k=;k<i;k++,w*=wn)
{
E x=a[j+k],y=w*a[j+k+i];
a[j+k]=x+y;a[j+k+i]=x-y;
}
}
}
}
inline int read()
{
char ch=getchar();int f=,x=;
while(ch<''||ch>'') {if(ch=='-') f=-f;ch=getchar();}
while(ch>=''&&ch<='') x=x*+ch-'',ch=getchar();
return x*f;
}
int main()
{
n=read();m=read();
for(int i=;i<=n;i++)a[i]=read();
for(int i=;i<=m;i++)b[i]=read();
m+=n;for(n=;n<=m;n<<=)l++;
for(int i=;i<n;i++)r[i]=(r[i>>]>>)|((i&)<<(l-));
FFT(a,);FFT(b,);
for(int i=;i<=n;i++)a[i]=a[i]*b[i];
FFT(a,-);
for(int i=;i<=m;i++)printf("%d ",(int)(a[i].real()/n+0.5));
}
附上一个高精度乘法,其实就是FFT的简单变形。
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define N 300005
#define pi acos(-1)
using namespace std;
typedef complex<double> E;
int n,m,l,r[N],ans[N];
E a[N],b[N];
char s[N];
void FFT(E *a,int f){
for(int i=;i<n;i++)if(i<r[i])swap(a[i],a[r[i]]);
for(int i=;i<n;i<<=)
{
E wn(cos(pi/i),f*sin(pi/i));
for(int p=i<<,j=;j<n;j+=p)
{
E w(,);
for(int k=;k<i;k++,w*=wn)
{
E x=a[j+k],y=w*a[j+k+i];
a[j+k]=x+y;a[j+k+i]=x-y;
}
}
}
}
inline int read()
{
char ch=getchar();int f=,x=;
while(ch<''||ch>'') {if(ch=='-') f=-f;ch=getchar();}
while(ch>=''&&ch<='') x=x*+ch-'',ch=getchar();
return x*f;
}
int main(){
n=read();n--;m=n;
scanf("%s",s);
for(int i=;i<=n;i++)a[i]=s[n-i]-'';
scanf("%s",s);
for(int i=;i<=m;i++)b[i]=s[m-i]-'';
m+=n;for(n=;n<=m;n<<=)l++;
for(int i=;i<n;i++)r[i]=(r[i>>]>>)|((i&)<<(l-));
FFT(a,);FFT(b,);
for(int i=;i<=n;i++)a[i]=a[i]*b[i];
FFT(a,-);
for(int i=;i<=m;i++)ans[i]=(int)(a[i].real()/n+0.5);
for(int i=;i<=m;++i)
ans[i+]+=ans[i]/,ans[i]%=;
if(ans[m+]) m++;
while(ans[m]==&&m) m--;
for(int i=m;i>=;--i) printf("%d",ans[i]);
}
FFT(快速傅里叶变换)的更多相关文章
- FFT 快速傅里叶变换 学习笔记
FFT 快速傅里叶变换 前言 lmc,ikka,attack等众多大佬都没教会的我终于要自己填坑了. 又是机房里最后一个学fft的人 早背过圆周率50位填坑了 用处 多项式乘法 卷积 \(g(x)=a ...
- CQOI2018 九连环 打表找规律 fft快速傅里叶变换
题面: CQOI2018九连环 分析: 个人认为这道题没有什么价值,纯粹是为了考算法而考算法. 对于小数据我们可以直接爆搜打表,打表出来我们可以观察规律. f[1~10]: 1 2 5 10 21 4 ...
- 「学习笔记」FFT 快速傅里叶变换
目录 「学习笔记」FFT 快速傅里叶变换 啥是 FFT 呀?它可以干什么? 必备芝士 点值表示 复数 傅立叶正变换 傅里叶逆变换 FFT 的代码实现 还会有的 NTT 和三模数 NTT... 「学习笔 ...
- FFT —— 快速傅里叶变换
问题: 已知A[], B[], 求C[],使: 定义C是A,B的卷积,例如多项式乘法等. 朴素做法是按照定义枚举i和j,但这样时间复杂度是O(n2). 能不能使时间复杂度降下来呢? 点值表示法: 我们 ...
- [C++] 频谱图中 FFT快速傅里叶变换C++实现
在项目中,需要画波形频谱图,因此进行查找,不是很懂相关知识,下列代码主要是针对这篇文章. http://blog.csdn.net/xcgspring/article/details/4749075 ...
- matlab中fft快速傅里叶变换
视频来源:https://www.bilibili.com/video/av51932171?t=628. 博文来源:https://ww2.mathworks.cn/help/matlab/ref/ ...
- FFT快速傅里叶变换算法
1.FFT算法概要: FFT(Fast Fourier Transformation)是离散傅氏变换(DFT)的快速算法.即为快速傅氏变换.它是根据离散傅氏变换的奇.偶.虚.实等特性,对离散傅立叶变换 ...
- FFT快速傅里叶变换
FFT太玄幻了,不过我要先膜拜HQM,实在太强了 1.多项式 1)多项式的定义 在数学中,由若干个单项式相加组成的代数式叫做多项式.多项式中的每个单项式叫做多项式的项,这些单项式中的最高项次数,就是这 ...
- [学习笔记]FFT——快速傅里叶变换
大力推荐博客: 傅里叶变换(FFT)学习笔记 一.多项式乘法: 我们要明白的是: FFT利用分治,处理多项式乘法,达到O(nlogn)的复杂度.(虽然常数大) FFT=DFT+IDFT DFT: 本质 ...
随机推荐
- 你不知道的Static
Static静态字段,静态方法,静态代码块 壹 简介 一些场景下会要求一个类的多个实例共享一个成员变量:有时候想定义一些不和具体对象关联.不需要new就调用的方法 举例:Console类的Write ...
- WordPress的SEO插件——WordPress SEO by yoast安装及使用
插件:WordPress SEO by yoast 使用方法: 做好网站SEO一直是站长们的愿望,说简单也简单,但是说难也难,因为需要注意的地方太多,一个不小心被百度K了你都不知道怎么回事.这里和大家 ...
- Arm-kernel 内存收集【转】
转自:http://blog.csdn.net/linyt/article/details/6627664 Linux kernel的内存管理子系统非常复杂,为了深入了解内存管理系统,我打算分多篇文章 ...
- elasticsearch集群介绍及优化【转】
elasticsearch用于构建高可用和可扩展的系统.扩展的方式可以是购买更好的服务器(纵向扩展)或者购买更多的服务器(横向扩展),Elasticsearch能从更强大的硬件中获得更好的性能,但是纵 ...
- Linux 查看网卡流量【转】
我的系统式RHEL5. 在linux下,查看网卡流量的方法有很多.下面先记录几个,和他们的大概用法.已被以后之需. 一:iptraf 一个很不错的工具.RHEL5 iso自带有,我 ...
- .htaccess技巧: URL重写(Rewrite)与重定向(Redirect)
URL重定向是.htaccess的重头戏,它可以将长地址转为短地址.将动态地址转为静态地址.重定向丢失的页面.防止盗链.实现自动语言转换等.笔者觉得难点是在正则表达式的运用和理解上. 实现所有这些神奇 ...
- AspNet Core 发布到Linux系统和发布IIS 注意项
AspNet Core 发布到Linux系统和发布IIS 注意项 1.发布时需要注意的 2.Windows Server 2012 api-ms-win-crt-runtime-l1-1-0.dll ...
- HDU 1495 非常可乐(BFS倒水问题)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1495 题目大意:只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101) ...
- (六)Spring4 整合Hibernate4,Struts2
第一节:S2SH 整合所需Jar 包 Struts2.3.16,Spring4.0.6,Hibernate4.3.5 整合所需jar 包: Struts2.3.16 jar 包 Spring4.0.6 ...
- 关于js函数 形参和局部变量名相同 的问题
原文:https://segmentfault.com/q/1010000007278354?_ea=1295176 问题: function f1(a) { console.log(a);// 10 ...