并不对劲的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时由于傅 ...
随机推荐
- Leetcode 319.灯泡开关
灯泡开关 初始时有 n 个灯泡关闭.第 1 轮,你打开所有的灯泡.第 2 轮,每两个灯泡你关闭一次.第 3 轮,每三个灯泡切换一次开关(如果关闭则开启,如果开启则关闭).第 i 轮,每 i 个灯泡切换 ...
- Oracle dataguard failover 实战
Oracle dataguard failover 实战 操作步骤 备库: SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE FINIS ...
- [luoguP2948] [USACO09OPEN]滑雪课Ski Lessons(DP)
传送门 f[i][j]表示i时刻能力值为j的最大滑雪数 显然f[0][1]=0,开始搜索 三种转移: ①美美的喝上一杯**:f[i+1][j]=max(f[i+1][j],f[i][j]) ②滑雪,f ...
- hdu 4421 和poj3678类似二级制操作(2-sat问题)
/* 题意:还是二进制异或,和poj3678类似 建边和poj3678一样 */ #include<stdio.h> #include<string.h> #include&l ...
- No route info of this topic
使用rocketmq时报错 com.alibaba.rocketmq.client.exception.MQClientException: No route info of this topic, ...
- ArrayList去除重复元素
去除一个ArrayList的重复元素有两种方法:(ArrayList与Vector的存储结构是Object[],LinkedList是双向列表) 第一种是不需要借助临时list,用equals方法比较 ...
- Netty 4.0 新的特性及需要注意的地方
Netty 4.0 新的特性及需要注意的地方 这篇文章和你一起过下Netty的主发行版本的一些显著的改变和新特性,让你在把你的应用程序转换到新版本的时候有个概念. 项目结构改变 Netty的包名从or ...
- [bzoj4199][Noi2015]品酒大会_后缀自动机_后缀树_树形dp
品酒大会 bzoj-4199 Noi-2015 题目大意:给定一个字符串,如果其两个子串的前$r$个字符相等,那么称这两个子串的开头两个位置$r$相似.如果两个位置勾兑在一起那么美味度为两个位置的乘积 ...
- 【Perl】perl正则表达式中的元字符、转义字符、量词及匹配方式
Linux平台上被广泛使用的正则表达式库PCRE - Perl-compatible regular expressions,从其名字即可知道,PCRE提供的是一套与Perl中相兼容的正则表达式. 元 ...
- [Angular] Write Compound Components with Angular’s ContentChild
Allow the user to control the view of the toggle component. Break the toggle component up into multi ...