FFT是一个很多人选择背诵全文的算法。

  1. #include<algorithm>
  2. #include<cmath>
  3. #include<complex>
  4. #include<cstdio>
  5. #include<cstdlib>
  6. #include<cstring>
  7. #include<ctime>
  8. #include<iomanip>
  9. #include<iostream>
  10. #include<map>
  11. #include<queue>
  12. #include<set>
  13. #include<stack>
  14. #include<vector>
  15. #define rep(i,x,y) for(register int i=(x);i<=(y);++i)
  16. #define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
  17. #define cd complex<double>
  18. #define maxn 1000110
  19. #define maxm (maxn<<1)
  20. using namespace std;
  21. int read()
  22. {
  23. int x=0,f=1;char ch=getchar();
  24. while(!isdigit(ch)&&ch!='-')ch=getchar();
  25. if(ch=='-')f=-1,ch=getchar();
  26. while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
  27. return x*f;
  28. }
  29. void write(int x)
  30. {
  31. if(x==0){putchar('0'),putchar('\n');return;}
  32. int f=0;char ch[20];
  33. if(x<0)putchar('-'),x=-x;
  34. while(x)ch[++f]=x%10+'0',x/=10;
  35. while(f)putchar(ch[f--]);
  36. putchar('\n');
  37. return;
  38. }
  39. const double pi=acos(-1);
  40. int n,m,r[maxm],len;
  41. cd a[maxm],b[maxm];
  42. void fft(cd * c,double f)
  43. {
  44. rep(i,0,n-1)if(i<r[i])swap(c[i],c[r[i]]);
  45. for(int i=1;i<n;i<<=1)
  46. {
  47. cd wn(cos(pi/i),sin(f*pi/i)),x,y;
  48. for(int j=0;j<n;j+=(i<<1))
  49. {
  50. cd w(1,0);
  51. rep(k,0,i-1)
  52. x=c[j+k],y=w*c[j+i+k],c[j+k]=x+y,c[j+i+k]=x-y,w*=wn;
  53. }
  54. }
  55. }
  56. int main()
  57. {
  58. n=read(),m=read();
  59. rep(i,0,n)a[i]=read();
  60. rep(i,0,m)b[i]=read();
  61. m+=n;
  62. for(n=1;n<=m;n<<=1)len++;
  63. rep(i,0,n-1)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
  64. fft(a,1),fft(b,1);
  65. rep(i,0,n-1)a[i]*=b[i];
  66. fft(a,-1);
  67. rep(i,0,m)printf("%d ",int(a[i].real()/n+0.5));
  68. return 0;
  69. }

并不对劲的大剑使认为有必要说明为什么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$$

\[\space\space\space=\sum_{i=0}^{n-1}{(\sum_{j=0}^{n-1}a_j*(\omega_n^i)^j)(\omega_n^{-k})^i}
\]

\[\space=\sum_{i=0}^{n-1}{\sum_{j=0}^{n-1}a_j*\omega_n^{i*j}*\omega_n^{-k*i}}
\]

\[=\sum_{i=0}^{n-1}{\sum_{j=0}^{n-1}a_j*\omega_n^{i*(j-k)}}\space\space\space\space\space
\]

\[=\sum_{j=0}^{n-1}{a_j*(\sum_{i=0}^{n-1}\omega_n^{i*(j-k)})}\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$$

\[a_k=\frac{z_k}{n}
\]

也就是说,IDFT相当于对当前多项式进行一次代入\(\omega_n^0,\omega_n^{-1},...,\omega_n^{-(n-1)}\)的DFT,再将每一项的系数除以n。

快速数论变化(FNTT)也是一个很多人选择背诵全文的算法。

只是把单位根换成了模意义下的原根而已

  1. #include<algorithm>
  2. #include<cmath>
  3. #include<complex>
  4. #include<cstdio>
  5. #include<cstdlib>
  6. #include<cstring>
  7. #include<ctime>
  8. #include<iomanip>
  9. #include<iostream>
  10. #include<map>
  11. #include<queue>
  12. #include<set>
  13. #include<stack>
  14. #include<vector>
  15. #define rep(i,x,y) for(int i=(x);i<=(y);++i)
  16. #define dwn(i,x,y) for(int i=(x);i>=(y);--i)
  17. #define cd complex<double>
  18. #define maxn 2000110
  19. #define maxm (maxn<<1)
  20. #define LL long long
  21. using namespace std;
  22. int read()
  23. {
  24. int x=0,f=1;char ch=getchar();
  25. while(!isdigit(ch)&&ch!='-')ch=getchar();
  26. if(ch=='-')f=-1,ch=getchar();
  27. while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
  28. return x*f;
  29. }
  30. void write(int x)
  31. {
  32. if(x==0){putchar('0'),putchar('\n');return;}
  33. int f=0;char ch[20];
  34. if(x<0)putchar('-'),x=-x;
  35. while(x)ch[++f]=x%10+'0',x/=10;
  36. while(f)putchar(ch[f--]);
  37. putchar('\n');
  38. return;
  39. }
  40. const double pi=acos(-1);
  41. const LL mod=998244353;
  42. int n,m,r[maxm],len;
  43. int a[maxm],b[maxm];
  44. int mul(int x,int y)
  45. {
  46. int ans=1;
  47. while(y)
  48. {
  49. if(y&1)ans=((LL)ans*(LL)x)%mod;
  50. x=((LL)x*(LL)x)%mod,y>>=1;
  51. }
  52. return ans;
  53. }
  54. void fntt(int * c,double f)
  55. {
  56. rep(i,0,n-1)if(i<r[i])swap(c[i],c[r[i]]);
  57. for(int i=1;i<n;i<<=1)
  58. {
  59. int wn=mul(3,(mod-1)/(i<<1)),x,y;
  60. if(f==-1)wn=mul(wn,mod-2);
  61. for(int j=0;j<n;j+=(i<<1))
  62. {
  63. int w=1;
  64. rep(k,0,i-1)
  65. 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;
  66. }
  67. }
  68. }
  69. int main()
  70. {
  71. n=read(),m=read();
  72. rep(i,0,n)a[i]=read();
  73. rep(i,0,m)b[i]=read();
  74. m+=n;
  75. for(n=1;n<m+1;n<<=1)len++;
  76. rep(i,0,n-1)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
  77. fntt(a,1),fntt(b,1);
  78. rep(i,0,n-1)a[i]=((LL)a[i]*(LL)b[i])%mod;
  79. fntt(a,-1);int inv=mul(n,mod-2);
  80. rep(i,0,m)printf("%d ",(LL)a[i]*(LL)inv%mod);
  81. return 0;
  82. }

并不对劲的DFT的更多相关文章

  1. 【算法•日更•第四十二期】离散傅里叶变换(DFT)

    ▎前言 小编相当的菜,这篇博客难度稍高,所以有些可能不会带有证明,博客中更多的是定义. 我们将要学到的东西: 复数 暴力多项式乘法 DFT 当然,小编之前就已经写过一篇博客了,主要讲的就是基础多项式, ...

  2. 转载:一幅图弄清DFT与DTFT,DFS的关系

    转载:http://www.cnblogs.com/BitArt/archive/2012/11/24/2786390.html 很多同学学习了数字信号处理之后,被里面的几个名词搞的晕头转向,比如DF ...

  3. 频域分辨率与DFT,DCT,MDCT理解

    搞了这么久音频算法,有些细节还没有很清楚. 比如DFT和DCT有哪些区别,DFT系数为什么会是对称的,同样帧长的数据,各自的频域分辨率是多少? 今天决定搞清楚这些问题, 首先DFT的系数对称(2N点的 ...

  4. 傅里叶:有关FFT,DFT与蝴蝶操作(转 重要!!!!重要!!!!真的很重要!!!!)

    转载地址:http://blog.renren.com/share/408963653/15068964503(作者 :  徐可扬) 有没有!!! 其实我感觉这个学期算法最难最搞不懂的绝对不是动态规划 ...

  5. DFT basics

    DFT测试中,最重要的部分还是sequential circuit的内部状态的测试. 起初ad hoc的方法用来提高testability,可以提高局部的coverage,但并不是一个系统性的方法. ...

  6. DFT设计绪论

    DFT设计的主要目的是为了将defect-free的芯片交给客户. 产品质量,通常使用Parts Per million(PPM)来衡量. 但是随着IC从SSI到VLSI的发展,在test上花销的时间 ...

  7. FS,FT,DFS,DTFT,DFT,FFT的联系和区别

    DCT变换的原理及算法 文库介绍 对于初学数字信号处理(DSP)的人来说,这几种变换是最为头疼的,它们是数字信号处理的理论基础,贯穿整个信号的处理. 学习过<高等数学>和<信号与系统 ...

  8. 【转】小解DCT与DFT

    这学期当本科生数字图像处理的助教老师,为使学生更好地理解DCF和DFT之间的关系给出三题,大家可以思考一下,看一下自己对这些最简单的变换是否真正理解. 1.求解序列f(n)=[2,3,3,4,4,3, ...

  9. 【转】由DFT推导出DCT

    原文地址:http://blog.sina.com.cn/s/blog_626631420100xvxd.htm 已知离散傅里叶变换(DFT)为: 由于许多要处理的信号都是实信号,在使用DFT时由于傅 ...

随机推荐

  1. BNUOJ 6378 无题I

    无题I Time Limit: 10000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 22346 ...

  2. zoj 2727 List the Books

    List the Books Time Limit: 2 Seconds      Memory Limit: 65536 KB Jim is fond of reading books, and h ...

  3. git clone, push, pull, fetch 的用法

    Git是目前最流行的版本管理系统,学会Git几乎成了开发者的必备技能. Git有很多优势,其中之一就是远程操作非常简便.本文详细介绍5个Git命令,它们的概念和用法,理解了这些内容,你就会完全掌握Gi ...

  4. 学习日常笔记<day14>自定义标签

    1自定义标签 1.1第一个自定义标签开发步骤 1)编写一个普通的java类,继承SimpleTagSupport类,叫标签处理器类 /** * 标签处理器类 * @author APPle * 1)继 ...

  5. java学习——关于java课件上动手动脑问题简单的分析

    问题一:关于以下的代码为什么会产生错误的问题的简单分析. 第一个动手动脑提供了一下的代码,可以发现,在Foo的这个类中只定义了一个Foo(int)类型的构造函数,在之前的学习工程中,我们并没有接触到j ...

  6. nginx.org与nginx.com有什么区别(Nginx与Nginx Plus)

    nginx.org是开源社区,管理着Nginx开源版. nginx.xom是商业社区,管理着Nginx Plus商业版. 商业版和开源版是有很大区别的,服务还加更强大的功能,当然依托开源社区加载第三方 ...

  7. kd树 hdu2966 In case of failure

    传送门:pid=2966" target="_blank">点击打开链接 题意:给n个点,求对于每一个点到近期点的欧几里德距离的平方. 思路:看鸟神博客学kd树劲啊 ...

  8. 【Mongodb教程 第六课 】MongoDB 插入文档

    insert() 方法 要插入数据到 MongoDB 集合,需要使用 MongoDB 的  insert() 或 save() 方法. 语法 insert() 命令的基本语法如下: >db.CO ...

  9. swagger 如何在UI界面加入Authentication token值

    接口 2.access_token 值: 3  输入值:bearer+空格+值

  10. rocketmq消费队列代码

    DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(Constant.operationLogGroup); try { consum ...