【清橙A1084】【FFT】快速傅里叶变换
对于一个给定的长度为n=2m (m为整数) 的复数序列X0, X1, …, Xn-1,离散傅立叶变换将得到另一个长度为n的复数序列Y0, Y1, …, Yn-1。其中
Yi=X0+X1wi+ X2w2i+ X3w3i+…+ Xn-1w(n-1)i
其中w=e2πI/n=cos(2π/n)+I sin(2π/n),称为旋转因子,其中I为虚数单位,I2= –1。
给定输入序列X,请输出傅立叶变换后的输出序列。
由于所有的复数C都可以表示成C=a+Ib的形式,即由实部和虚部的和表示,所以C可以用一个二元组(a, b)来表示,用这种方法w可表示为(cos(2π/n), sin(2π/n))。复数的计算规则如下:
(a1, b1)+(a2, b2)=(a1+a2, b1+b2)
(a1, b1)(a2, b2)=(a1, b1)*(a2, b2)=(a1*a2-b1*b2, a1*b2+a2*b1)
对于本题,你可以按照上面的公式直接计算,也可以按下面的方法计算。使用上面的公式的复杂度为O(n2),可以得到一半的分数,而下面的方法的复杂度为O(n log n),可以得到全部的分数。如果要使用上面的公式直接计算,请跳过下面的算法描述部分。
对上面的公式进行变形,得到:
Yi
=X0 + X1wi + X2w2i + X3w3i +…+ Xn-1w(n-1)i
=X0 + X2w2i + X4w4i +…+ Xn-2w(n-2)i + wi(X1 + X3w2i + X5w4i +…+ Xn-1w(n-2)i)
=(X0 + X2φi + X4φ2i +…+ Xn-2φ(n/2-1)i) + wi(X1 + X3φi + X5φ2i +…+ Xn-1φ(n/2-1)i)
其中φ=w2。利用这个公式可得
Yi+n/2=(X0 + X2φi+n/2 + X4φ2(i+n/2) +…+ Xn-2φ(n/2-1) (i+n/2)) + wi(X1 + X3φ(i+n/2) + X5φ2(i+n/2) +…+ Xn-1φ(n/2-1) (i+n/2))
其中φi+n/2=w2i+n=w2i=φi。
所以当i<n/2时,令pi=X0 + X2φi + X4φ2i +…+ Xn-2φ(n/2-1)i,qi= X1 + X3φi + X5φ2i +…+ Xn-1φ(n/2-1)i,则Yi=pi+wiqi,Yi+n/2= pi+wi+n/2qi。
利用上面的公式,我们可以得到一种快速计算旋转因子为w的傅立叶变换的方法如下(快速傅立叶变换):
算法Y=Fourier(X, n, w)
参数:X={Xi}为待变换的序列,n为序列的长度(2的整数次幂),w为旋转因子
结果:X的傅立叶变换Y={Yi}
1. 计算{X0, X2, X4, …, Xn-2}在旋转因子为φ=w2时的傅立叶变换序列{pi}
2. 计算{ X1, X3, X5, …, Xn-1}在旋转因子为φ=w2时的傅立叶变换序列{qi}
3. 对于0<=i<n,计算Yi=pi+wiqi。其中w0=(1, 0),wi=wi-1*w,你要设置一个临时变量进行累乘而不能每次重新计算wi。
使用这种方法,即可在O(n log n)的时间内计算傅立叶变换。
接下来n行,每行2个实数a, b表示序列中的一个元素为(a, b)。
1.0 0.0
1.0 0.0
0.0 0.0
0.0 0.0
0.25 0.25
0.00 0.00
0.25 -0.25
/*
宋代苏轼
《临江仙·夜饮东坡醒复醉》
夜饮东坡醒复醉,归来仿佛三更。家童鼻息已雷鸣。敲门都不应,倚杖听江声。
长恨此身非我有,何时忘却营营。夜阑风静縠纹平。小舟从此逝,江海寄余生。
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#include <iostream>
#include <string>
#include <ctime>
#define LOCAL
const double Pi = acos(-1.0);
const int MAXN = + ;
using namespace std;
typedef long long ll;
struct Num {
double a , b;
//构造函数
Num(double x = ,double y = ) {a = x; b = y;}
//复数的三种运算
Num operator + (const Num &c) {return Num(a + c.a, b + c.b);}
Num operator - (const Num &c) {return Num(a - c.a, b - c.b);}
Num operator * (const Num &c) {return Num(a * c.a - b * c.b, a * c.b + b * c.a);}
}x1[MAXN] , x2[MAXN]; //注意loglen为log后的长度
void change(Num *t, int len, int loglen){
//蝶形变换后的序列编号
for (int i = ; i < len; i++){
int x = i, k = ;
for (int j = ; j < loglen; j++, x >>= ) k = (k << ) | (x & );
if (k < i) swap(t[k], t[i]);
}
}
//基2-FFT
void FFT(Num *x, int len, int loglen){
change(x, len, loglen);
int t = ;
//t为长度
for (int i = ; i < loglen; i++, (t <<= )){
int l = , r = l + t;
while (l < len){
//初始化
Num a, b, wo(cos(Pi / t), sin(Pi / t)), wn(, );
for (int j = l; j < l + t; j++){
a = x[j];
b = x[j + t] * wn;
//蝶形计算
x[j] = a + b;
x[j + t] = a - b;
wn = wn * wo;
}
//注意是合并所以要走2t步
l = r + t;
r = l + t;
}
}
}
//离散傅里叶变换
void DFT(Num *x, int len, int loglen){
int t = (<<loglen);
for (int i = ; i < loglen; i++){
t >>= ;
int l = , r = l + t;
while (l < len){
Num a, b, wn(, ), wo(cos(Pi / t), -sin(Pi / t));
for (int j = l; j < l + t; j++){
a = x[j] + x[j + t];
b = (x[j] - x[j + t]) * wn;
x[j] = a;
x[j + t] = b;
wn = wn * wo;
}
l = r + t;
r = l + t;
}
}
change(x, len, loglen);
for (int i= ; i < len; i++) x[i].a /= len;
}
int solve(char *a, char *b){
int len1, len2, len, loglen;
int t, over;
len1 = strlen(a) << ;
len2 = strlen(b) << ;
len = ;
loglen = ;
while (len < len1) len <<= , loglen++;
while (len < len2) len <<= , loglen++;
//处理len1
for (int i = ; i < len; i++){
if (a[i]) x1[i].a = a[i] - '', x1[i].b = ;
else x1[i].a = x1[i].b = ;
}
for (int i = ; i < len; i++){
if (b[i]) x2[i].a = b[i] - '', x2[i].b = ;
else x2[i].a = x2[i].b = ;
}
FFT(x1, len, loglen);
FFT(x2, len, loglen);
for (int i = ; i < len; i++) x1[i] = x1[i] * x2[i]; DFT(x1, len, loglen);
over = len = ;
//转换成十进制的整数
for (int i = ((len1 + len2) / ) - ; i >= ; i--){
t = (int)((double)x1[i].a + (double)over + 0.5);
a[len++] = t % ;
over = t / ;
}
while (over){
a[len++] = over % ;
over /= ;
}
return len;
}
//输出
void print(char *str, int len){
for(len--; len>= && !str[len];len--);
if(len < ) putchar('');
else for(;len>=;len--) putchar(str[len]+'');
printf("\n");
}
char a[MAXN] , b[MAXN]; int main() {
int n; scanf("%d", &n);
for (int i = ; i < n; i++) scanf("%lf%lf", &x1[i].a, &x1[i].b);
int t = ;
while ((<<t) < n) t++;
FFT(x1, n, t);
for (int i = ; i < n; i++) printf("%.2lf %.2lf\n", x1[i].a / n, x1[i].b / n);
return ;
}
【清橙A1084】【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: 本质 ...
随机推荐
- HDOJ/HDU 1022 Train Problem I(模拟栈)
Problem Description As the new term comes, the Ignatius Train Station is very busy nowadays. A lot o ...
- 2013 ACM区域赛长沙 K Pocket Cube hdu 4801
题意:给了一个2*2的魔方..每步操作可以将任意一面翻转90度..现在问在N(<=7)步内.最多能翻出几面相同的. 直接打表模拟每种翻转情况 #include<cstdio> #in ...
- Dot Net设计模式—MVC模式
1 MVC设计模式简介 MVC结构是为那些需要为同样的数据提供多个视图的应用程序而设计的,它很好的实现了数据层与表示层的分离.MVC作为一种开发模型,通常用于分布式应用系统的设计和分析中,以及用于确定 ...
- Python的高级特性之切片、迭代、列表生成式、生成器
切片 切片就是获取一个list.tuple.字符串等的部分元素 l = range(100) #取[0,5)元素 print(l[:5]) #[0, 1, 2, 3, 4] #在[0,99]中每隔10 ...
- Jackson中的那些坑
不符合驼峰规范的变量 “驼峰命名法”请自行百度.简单的来说就是变量的第一个单词以小写字母开始其他单词首字母大写,或者全部单词首字母都大写,分别称为“小驼峰”和“大驼峰” 比如一个符合驼峰规范命名的实体 ...
- HttpURLConnection的流式输出的缺陷和解决方法
转自:http://www.mzone.cc/article/198.html 最近在用applet写文件上传控件的时候发现使用URLConnection来对服务器进行流式输出时的一些问题.我们通常要 ...
- 网上下载的 java开源项目 如何 打jar包
目前很多java开源项目(例如qlexpress)只提供了源码,没有提供jar,下面提供maven打jar包的方法. 1.进入qlexpress下载后源代码所在的目录,此目录应包含pom.xml,如下 ...
- git push 报错
git push报错误: Git push error: RPC failed; result=56, HTTP code = 200 fatal: The remote end hung up un ...
- 使用 OpenSSL API 进行安全编程
创建基本的安全连接和非安全连接 Kenneth Ballard ( kenneth.ballard@ptk.org), 自由程序员 Kenneth 是 Peru State College(位于 Pe ...
- PMP考试的过与只是
我在一年多时间里參加了三次PMP考试,前两次都失败,直到第三次才成功.怎样对待失败?这是每个人都会遇到的挑战.假设我们能用正确的态度对待临时的失败,那么终于的成功也就不远了.我希望通过本文与大家分享一 ...