并不对劲的DFT
FFT是一个很多人选择背诵全文的算法。
#include<algorithm>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define cd complex<double>
#define maxn 1000110
#define maxm (maxn<<1)
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
if(x==0){putchar('0'),putchar('\n');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
return;
}
const double pi=acos(-1);
int n,m,r[maxm],len;
cd a[maxm],b[maxm];
void fft(cd * c,double f)
{
rep(i,0,n-1)if(i<r[i])swap(c[i],c[r[i]]);
for(int i=1;i<n;i<<=1)
{
cd wn(cos(pi/i),sin(f*pi/i)),x,y;
for(int j=0;j<n;j+=(i<<1))
{
cd w(1,0);
rep(k,0,i-1)
x=c[j+k],y=w*c[j+i+k],c[j+k]=x+y,c[j+i+k]=x-y,w*=wn;
}
}
}
int main()
{
n=read(),m=read();
rep(i,0,n)a[i]=read();
rep(i,0,m)b[i]=read();
m+=n;
for(n=1;n<=m;n<<=1)len++;
rep(i,0,n-1)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
fft(a,1),fft(b,1);
rep(i,0,n-1)a[i]*=b[i];
fft(a,-1);
rep(i,0,m)printf("%d ",int(a[i].real()/n+0.5));
return 0;
}
并不对劲的大剑使认为有必要说明为什么IDFT最后要除以n。
假设原函数是\(F(x)=a_0x^0+a_1x^1+...+a_{n-1}x^{n-1}\)
那么对它进行DFT,将\(\omega_n^0,\omega_n^1,...,\omega_n^{n-1}\)依次代入,得到\(y_0,y_1,...,y_{n-1}\)
设\(G(x)=y_0x^0+y_1x^1+...+y_{n-1}x^{n-1}\)
IDFT就是已知G每一项的系数,求F每一项的系数
先对G进行DFT,将\(\omega_n^0,\omega_n^{-1},...,\omega_n^{-(n-1)}\)依次代入,得到\(z_0,z_1,...,z_{n-1}\)
那么就会有$$z_k=\sum_{i=0}{n-1}{y_i*(\omega_n{-k})^i}\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space$$
\]
\]
\]
\]
可以将$$\sum_{i=0}{n-1}\omega_n{i(j-k)}$$这部分看成一个首项为1,公比为\(\omega_n^{j-k}\)的等比数列,那么由等比数列求和公式可知:
当\(j-k\neq0\)时,$$\sum_{i=0}{n-1}\omega_n{i(j-k)}=\frac{(\omega_n{j-k})n-1}{\omega_n{j-k}-1}=\frac{(\omega_nn){j-k}-1}{\omega_n{j-k}-1}=\frac{(\omega_n0){j-k}-1}{\omega_n{j-k}-1}=\frac{1{j-k}-1}{\omega_n^{j-k}-1}=0$$
当\(j-k=0\)时,$$\sum_{i=0}{n-1}\omega_n{i(j-k)}=\sum_{i=0}{n-1}\omega_n{i0}=\sum_{i=0}^{n-1}1=n$$
这样就有$$z_k=a_k*n$$
\]
也就是说,IDFT相当于对当前多项式进行一次代入\(\omega_n^0,\omega_n^{-1},...,\omega_n^{-(n-1)}\)的DFT,再将每一项的系数除以n。
快速数论变化(FNTT)也是一个很多人选择背诵全文的算法。
只是把单位根换成了模意义下的原根而已
#include<algorithm>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(int i=(x);i>=(y);--i)
#define cd complex<double>
#define maxn 2000110
#define maxm (maxn<<1)
#define LL long long
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
if(x==0){putchar('0'),putchar('\n');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
return;
}
const double pi=acos(-1);
const LL mod=998244353;
int n,m,r[maxm],len;
int a[maxm],b[maxm];
int mul(int x,int y)
{
int ans=1;
while(y)
{
if(y&1)ans=((LL)ans*(LL)x)%mod;
x=((LL)x*(LL)x)%mod,y>>=1;
}
return ans;
}
void fntt(int * c,double f)
{
rep(i,0,n-1)if(i<r[i])swap(c[i],c[r[i]]);
for(int i=1;i<n;i<<=1)
{
int wn=mul(3,(mod-1)/(i<<1)),x,y;
if(f==-1)wn=mul(wn,mod-2);
for(int j=0;j<n;j+=(i<<1))
{
int w=1;
rep(k,0,i-1)
x=c[j+k]%mod,y=((LL)w*(LL)c[j+i+k])%mod,c[j+k]=(x+y)%mod,c[j+i+k]=(x-y+mod)%mod,w=(LL)w*(LL)wn%mod;
}
}
}
int main()
{
n=read(),m=read();
rep(i,0,n)a[i]=read();
rep(i,0,m)b[i]=read();
m+=n;
for(n=1;n<m+1;n<<=1)len++;
rep(i,0,n-1)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
fntt(a,1),fntt(b,1);
rep(i,0,n-1)a[i]=((LL)a[i]*(LL)b[i])%mod;
fntt(a,-1);int inv=mul(n,mod-2);
rep(i,0,m)printf("%d ",(LL)a[i]*(LL)inv%mod);
return 0;
}
并不对劲的DFT的更多相关文章
- 【算法•日更•第四十二期】离散傅里叶变换(DFT)
▎前言 小编相当的菜,这篇博客难度稍高,所以有些可能不会带有证明,博客中更多的是定义. 我们将要学到的东西: 复数 暴力多项式乘法 DFT 当然,小编之前就已经写过一篇博客了,主要讲的就是基础多项式, ...
- 转载:一幅图弄清DFT与DTFT,DFS的关系
转载:http://www.cnblogs.com/BitArt/archive/2012/11/24/2786390.html 很多同学学习了数字信号处理之后,被里面的几个名词搞的晕头转向,比如DF ...
- 频域分辨率与DFT,DCT,MDCT理解
搞了这么久音频算法,有些细节还没有很清楚. 比如DFT和DCT有哪些区别,DFT系数为什么会是对称的,同样帧长的数据,各自的频域分辨率是多少? 今天决定搞清楚这些问题, 首先DFT的系数对称(2N点的 ...
- 傅里叶:有关FFT,DFT与蝴蝶操作(转 重要!!!!重要!!!!真的很重要!!!!)
转载地址:http://blog.renren.com/share/408963653/15068964503(作者 : 徐可扬) 有没有!!! 其实我感觉这个学期算法最难最搞不懂的绝对不是动态规划 ...
- DFT basics
DFT测试中,最重要的部分还是sequential circuit的内部状态的测试. 起初ad hoc的方法用来提高testability,可以提高局部的coverage,但并不是一个系统性的方法. ...
- DFT设计绪论
DFT设计的主要目的是为了将defect-free的芯片交给客户. 产品质量,通常使用Parts Per million(PPM)来衡量. 但是随着IC从SSI到VLSI的发展,在test上花销的时间 ...
- FS,FT,DFS,DTFT,DFT,FFT的联系和区别
DCT变换的原理及算法 文库介绍 对于初学数字信号处理(DSP)的人来说,这几种变换是最为头疼的,它们是数字信号处理的理论基础,贯穿整个信号的处理. 学习过<高等数学>和<信号与系统 ...
- 【转】小解DCT与DFT
这学期当本科生数字图像处理的助教老师,为使学生更好地理解DCF和DFT之间的关系给出三题,大家可以思考一下,看一下自己对这些最简单的变换是否真正理解. 1.求解序列f(n)=[2,3,3,4,4,3, ...
- 【转】由DFT推导出DCT
原文地址:http://blog.sina.com.cn/s/blog_626631420100xvxd.htm 已知离散傅里叶变换(DFT)为: 由于许多要处理的信号都是实信号,在使用DFT时由于傅 ...
随机推荐
- PTA 02-线性结构3 Reversing Linked List (25分)
题目地址 https://pta.patest.cn/pta/test/16/exam/4/question/664 5-2 Reversing Linked List (25分) Given a ...
- Toad Oracle 本地/远程数据库导入/导出 数据库备份
1. Toad进入数据库后,选择 Database ==> Export ===> Export Utility Wizard ,选择export user(按用户导出),选择Toa ...
- 【NOIP模拟】数字对(RMQ,二分)
题意:小H是个善于思考的学生,现在她又在思考一个有关序列的问题. 她的面前浮现出一个长度为n的序列{ai},她想找出一段区间[L, R](1 <= L <= R <= n). 这个特 ...
- msp430项目编程14
msp430中项目---电子测重系统 1.hx711工作原理 2.电路原理说明 3.代码(显示部分) 4.代码(功能实现) 5.项目总结 msp430项目编程 msp430入门学习
- HDU1533 最小费用最大流
Going Home Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- softmax函数理解
https://www.zhihu.com/question/23765351 因为这里不太方便编辑公式,所以很多公式推导的细节都已经略去了,如果对相关数学表述感兴趣的话,请戳这里的链接Softm ...
- codechef Polo the Penguin and the Tree
一般xor 的题目都是用trie解决. 那这道题是在树上的trie; 首先:从root==1,遍历树得到1到所有节点的xor 值. 然后对于每个点我们把其插入二进制树中. 对于每一个点查找其二进值异或 ...
- 选带傅里叶变换(zoom-fft)
选带傅里叶变换的原理大家能够看书.大致的步骤为 移频 (将选带的中心频率移动到零频) 数字低通滤波器 (防止频率混叠) 又一次採样 (将採样的数据再次间隔採样,间隔的数据取决于分析的带宽,就是放大 ...
- js获取get传递的值
<script language="javascript" src="js/jquery-1.9.0.min.js"></script> ...
- RabbitMQ通过shovel插件迁移数据
前言 生产环境中会遇到RabbitMQ数据迁移的场景,例如:切换云服务厂商.不同Region之间数据迁移.新搭建RabbitMQ实例,数据需要同步至新的RabbitMQ实例. 前提条件: 源Rabbi ...