FFT学习笔记

1.什么事FFT?(恼

百度百科传送门

2.为什么要用FFT?

  • 在计算两个多项式相乘的时候,我们要将两个多项式的项数一一对应相乘。

  • 所以计算 f ( x ) ∗ g ( x ) f(x)*g(x) f(x)g(x) 时,时间复杂度为 O ( n 2 ) O(n^2) O(n2)

  • 但是我们可以将函数用另一种表示方法。

  • 总所周知,用 n + 1 n+1 n+1 个点可以确定一个 n n n 次的函数(传送门),所以我们不妨写成(以 f ( x ) f(x) f(x)为例)

    f ( x ) = { ( x 0 , f ( x 0 ) ) , ( x 1 , f ( x 1 ) ) , . . . , ( x n , f ( x n ) ) } f(x)= \{(x0,f(x0)),(x1,f(x1)),...,(xn,f(xn))\} f(x)={(x0,f(x0)),(x1,f(x1)),...,(xn,f(xn))}

    即用坐标表示一个多项式函数。

  • 但有什么用呢?

    假设我们要求 f ( x ) ∗ g ( x ) f(x)*g(x) f(x)g(x)(设 f ( x ) , g ( x ) f(x),g(x) f(x)g(x) 的次数为 n n n)的结果(自然也是一个多项式,设为 h ( x ) h(x) h(x) 罢)

    若我们用坐标来求解,那么

    h ( x ) = { ( x 0 , f ( x 0 ) ∗ g ( x 0 ) ) , ( x 1 , f ( x 1 ) ∗ g ( x 1 ) ) , . . . , ( x n , f ( x n ) ∗ g ( x n ) ) } h(x)= \{ (x0,f(x0)*g(x0)),(x1,f(x1)*g(x1)),...,(xn,f(xn)*g(xn))\} h(x)={(x0,f(x0)g(x0)),(x1,f(x1)g(x1)),...,(xn,f(xn)g(xn))}

    O ( n ) O(n) O(n) 的。

  • 但是很可惜,多项式表示变换为坐标的时间复杂度事 O ( n 2 ) O(n^2) O(n2) 的(恼

    因为你不仅要枚举 n + 1 n+1 n+1 个不同的 x x x ,还要将每一个 x x x 带入。

    所以这时候就要用到 F F T FFT FFT

3.FFT代码

已经有人讲的很详细了,再详细也没有用了罢(悲

所以不再赘述了,链接直接贴出来(这事会员制博客,作者受到的惩罚是。。。(悲):

LeeCongWei
【学习笔记】极其美妙的算法——FFT(快速傅里叶变换)

路人黑的纸巾
十分简明易懂的FFT(快速傅里叶变换)

lahlah_
浅谈 FFT (终于懂一点了~~)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<complex>
#define co complex<double>
#define pi acos(-1.0)
using namespace std;
int n,m;
long long limt=1;
co a[4000200],b[4000200];
int rev[4000200];
void fft(co *c,int inv)
{
	for(int i=0;i<limt;i++)
	if(i<rev[i]) swap(c[rev[i]],c[i]);
	for(int mid=1;mid<limt;mid<<=1)
	{
		int len=mid*2;
		co w(cos(pi/mid),inv*sin(pi/mid));
		for(int i=0;i<limt;i+=len)
		{
			co omega(1,0);
			for(int j=0;j<mid;j++)
			{
				co p1=c[i+j],p2=omega*c[i+j+mid];
				c[i+j]=p1+p2;
				c[i+j+mid]=p1-p2;
				omega=w*omega;
			}		
		}
	}
}
int main()
{
	scanf("%d %d",&n,&m);
	for(int i=0;i<=n;i++)
	cin>>a[i];
	for(int i=0;i<=m;i++)
	cin>>b[i];
	while(limt<n+m+1)
	limt*=2;
	for(int i=0;i<limt;i++)
	if(i&1)
	rev[i]=((rev[i>>1]>>1)+limt/2);
	else
	rev[i]=(rev[i>>1]>>1);
	fft(a,1),fft(b,1);
	for(int i=0;i<limt;i++)
	a[i]*=b[i];
	fft(a,-1);
	for(int i=0;i<=n+m;i++)
	printf("%d ",(int)(a[i].real()/limt+0.5));
}

作者只是个背板子的食雪汉(悲

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值