模意义下的FFT算法

//写在前面 单就FFT算法来说的话,下面只给出个人认为比较重要的推导,详细的介绍可参考  FFT算法学习笔记

令v[n]是长度为2N的实序列,V[k]表示该实序列的2N点DFT。定义两个长度为N的实序列g[n]和h[n]为

 g[n]=v[2n],  h[n]=v[2n+1],  0<=n<N 

则可进行如下推导

这里所用的FFT算法能够实现O(nlogn)复杂度的离散傅里叶变换和上面最后所得的关系密切相关。

 

下面进入正题——模意义下的FFT

还是需要先了解一下关于 复序列的DFT的对称性质及一些补充定义 

由此,可以试想,假设说要模的素数p为1e8级别大小,那么我们可以把原始的实序列x[n]“拆”一下。

下面假设我们要求的是x[n]卷积y[n]的结果t[n]。

假设q是sqrt(p)级别的一个数,我们可以把x[n]/q存到复序列x1[n]的实部,x[n]%q存到复序列x1[n]的虚部。这时,对x1[n]、y1[n]求DFT,再由X1[k]*Y1[k]得到T1[k],整个运算过程中能够产生的最大浮点数为N*q^2级别,一般来说还是在可以接受的范围内的。

接下来考虑从卷积结果{T1[k]}中恢复出原始的t[n]的过程。

看一下T1[k]的组成

到这里差不多就可以结束了。发现上面最后一行等号右边有四个“乘积”,我们可以把上面四个乘积分别单独拿出来,求IDFT就可以恢复出x/y_re/im卷积的结果,之后针对不同的乘积,考虑需要在模p意义下乘上q^2、q^1或q^0,来进行恢复就可以了。

奉上模板

namespace FFT_MO    //前面需要有 mod(1e8~1e9级别),upmo(a,b) 的定义 
{const int FFT_MAXN=1<<18;const db pi=3.14159265358979323846264338327950288L;struct cp{db a,b;cp(double a_=0,double b_=0){a=a_,b=b_;}cp operator +(const cp&rhs)const{return cp(a+rhs.a,b+rhs.b);}cp operator -(const cp&rhs)const{return cp(a-rhs.a,b-rhs.b);}cp operator *(const cp&rhs)const{return cp(a*rhs.a-b*rhs.b,a*rhs.b+b*rhs.a);}cp operator !()const{return cp(a,-b);}}nw[FFT_MAXN+1],f[FFT_MAXN],g[FFT_MAXN],t[FFT_MAXN];    //a<->f,b<->g,t<~>c int bitrev[FFT_MAXN]; void fft_init()    //初始化 nw[],bitrev[] 
    {int L=0;while((1<<L)!=FFT_MAXN) L++;for(int i=1;i<FFT_MAXN;i++)  bitrev[i]=bitrev[i>>1]>>1|((i&1)<<(L-1));for(int i=0;i<=FFT_MAXN;i++) nw[i]=cp((db)cosl(2*pi/FFT_MAXN*i),(db)sinl(2*pi/FFT_MAXN*i));}// n已保证是2的整数次幂 // flag=1:DFT |  flag=-1: IDFTvoid dft(cp *a,int n,int flag=1)    {int d=0;while((1<<d)*n!=FFT_MAXN) d++;for(int i=0;i<n;i++) if(i<(bitrev[i]>>d))swap(a[i],a[bitrev[i]>>d]);for(int l=2;l<=n;l<<=1){int del=FFT_MAXN/l*flag;    // 决定 wn是在复平面是顺时针还是逆时针变化,以及变化间距 for(int i=0;i<n;i+=l){cp *le=a+i,*ri=a+i+(l>>1);cp *w=flag==1? nw:nw+FFT_MAXN;    // 确定wn的起点 for(int k=0;k<(l>>1);k++){cp ne=*ri * *w;*ri=*le-ne,*le=*le+ne;le++,ri++,w+=del;}}}if(flag!=1) for(int i=0;i<n;i++) a[i].a/=n,a[i].b/=n;}// convo(a,n,b,m,c) a[0..n]*b[0..m] -> c[0..n+m]void convo(LL *a,int n,LL *b,int m,LL *c){for(int i=0;i<=n+m;i++) c[i]=0;int N=2;while(N<=n+m) N<<=1;    // N是c扩展后的长度 for(int i=0;i<N;i++)    //扩展 a[],b[] ,存入f[],g[],注意取模 
        {LL aa=i<=n?a[i]:0,bb=i<=m? b[i]:0;     aa%=mod,bb%=mod;f[i]=cp(db(aa>>15),db(aa&32767));g[i]=cp(db(bb>>15),db(bb&32767));}dft(f,N),dft(g,N);for(int i=0;i<N;i++)    // 恢复虚部两个“乘积”(乘积具体意义见上文)
        {int j=i? N-i:0;t[i]=((f[i]+!f[j])*(!g[j]-g[i])+(!f[j]-f[i])*(g[i]+!g[j]))*cp(0,0.25);}dft(t,N,-1);for(int i=0;i<=n+m;i++)    upmo(c[i],(LL(t[i].a+0.5))%mod<<15);for(int i=0;i<N;i++)    // 恢复实部两个“乘积”
        {int j=i? N-i:0;t[i]=(!f[j]-f[i])*(!g[j]-g[i])*cp(-0.25,0)+cp(0,0.25)*(f[i]+!f[j])*(g[i]+!g[j]);}dft(t,N,-1);for(int i=0;i<=n+m;i++)    upmo(c[i],LL(t[i].a+0.5)+(LL(t[i].b+0.5)%mod<<30));}
}
模板

举个栗子~   hdu 6088 Rikka with Rock-paper-scissors (2017 多校第五场 1004) 【组合数学 + 数论 + 模意义下的FFT】

 

//本博客主要参考资料:数字信号处理——基于计算机的方法(第四版)  [美] Sanjit K. Mitra 著  余翔宇 译

转载请注明出处 http://www.cnblogs.com/Just--Do--It/p/7892254.html

谢谢阅读

 

转载于:https://www.cnblogs.com/Just--Do--It/p/7892254.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/251480.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

bootstrap --- 标签页切换

很多时候,我们希望写一个简单的标签页.以下使用bootstrap来实现… 首先导入bootstrap的依赖:jquery的依赖、bootstrap的依赖 注意: jquery的依赖要在bootstrap依赖的前面导入,原因是:bootstrap的某些功能是在jquery的基础上实现的 在 https://www.bootcdn.cn/jquery/ 导入jqu…

bootstrap --- 鼠标停留提示事件

使用bootstrap可以很简单的实现鼠标停留,提示的效果 <a href"#" data-toggle"tooltip" data-placement"right" title"Tooltip on right" class"btn btn-primary">工具提示</a> // data-toggle"tooltip&…

day 3 list列表生成式

1.定义一个list列表&#xff0c;里面元素是0-33 a []i 0 while i<33:a.append(i)i1print(a) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32] 2.range &#xff08;切片&#xff09; 1&…

2020校招前端知识点整理

自用的前端知识点整理笔记&#xff08;长期更新&#xff09; 开启面试造火箭模式&#x1f4d4;&#x1f448;点击获得更好的阅读体验 有错误的地方请指出&#xff0c;感激不尽 HTML 你是如何理解HTML语义化的&#xff1f;⭐ 总结&#xff1a;用恰当的标签来标记内容。 比如…

Android studio导入support-v4.jar

support-v4.jar是support library。路径为<sdk>/extras/android/support/v4/android-support-v4.jar.转载于:https://www.cnblogs.com/Magina-learning/p/7899788.html

编程学习笔记(第三篇)面向对象技术高级课程:绪论-软件开发方法的演化与最新趋势(3)软件开发的现状、UML扩展...

一、软件开发的现状 软件领域正在发生一个巨变&#xff0c;特别是近几年来&#xff0c;软件领域正在发生翻天覆地的变化。 这一变化主要以这个云 端大数据&#xff0c; 这些是随着目前最先进的一些技术的产生而产生的。 随着这些新的技术以及软件开发方法的不断的提升&#xf…

html5 --- canvas绘制网格并画x、y轴

效果如下: // 代码如下: <body><canvas width"500" height"375" id"c"></canvas><script>(function draw_a() {var a_canvas document.getElementById("c");var context a_canvas.getContext("2d&qu…

系统调用软中断处理程序system_call分析

最近学习了系统调用的整个流程&#xff0c;这里总结并记录。同时作为学习孟宁老师的linux内核课程的作业。 唐建&#xff0c;《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 1、概述 系统调用整个过程为&#xff1a;API——封装例程——system_c…

html5 --- 使用canvas画一个渐变矩形

我们希望得到如下效果: 首先准备画布 // HTML <canvas width"500" height"375" id "a"> </canvas>// JS // 获取画布的DOM元素 var a_canvas document.getElementById("1"); // 获取画布的上下文元素(之后,就可以使用…

vue --- 使用vue在html上显示当前时间

希望如下效果(时间按秒钟更新) 导入Vue依赖的CDN <script src"https://unpkg.com/vue/dist/vue.min.js"> </script>创建视图 <div id"app">{{date}}</div>Model <script>var app new Vue({el: "app",data: …

vue --- 购物车页面

下面我看开始自己写一个购物车的页面. 我们希望得到如下的效果: 说明: 购买数量最小为0购买数量变化时,对应的总价随之变化点击移除操作对应的商品会移除掉,总价随之改变每个商品作为一个list表的一个对象每个对象,包含id、name、price、count等属性 index.html (整体代码最…

vue --- 从模块从父元素获取数据

vue的精彩之处在于其组件的可复用性.下面谈谈组件(component)如何从父元素获取数据 模块引用 首先说说,如何引用模块 <div id"app"><my-component ></my-component> </div> <script src“unpkg.com/vue/dist/vue.min.js”> </…

前端知识总结(一)

1、用原生JS实现forEach if(!Array.prototype.forEach) {Array.prototype.forEach function(fn, context) {var context arguments[1];if(typeof fn ! "function") {throw new TypeError(fn "is not a function");}for(var i 0; i < this.length; …

vue --- 模块从子组件获取数据

先看个一般的例子: // 我们需要将信息从子组件传递给父组件,(有可能不止一条信息,因此)肯定需要一个标识,这个标识放在$emit里面(js),在dom中通过来关联父元素。如下:<div id "app"><transfer connect"sayConnect" build"sayBuild"&g…

mySql配置在nodejs中使用

mySql安装完成后&#xff0c;配置链接nodejs项目中的数据库。 1、测试是否安装成功。 2、use nodejs使用nodejs 3、设置数据源 5、exit 转载于:https://www.cnblogs.com/zhxzh/p/9244996.html

前端知识总结(二)

33、闭包 闭包的概念 上一节代码中的f2函数&#xff0c;就是闭包。 各种专业文献上的"闭包"&#xff08;closure&#xff09;定义非常抽象&#xff0c;很难看懂。我的理解是&#xff0c;闭包就是能够读取其他函数内部变量的函数。 由于在Javascript语言中&#x…

前端知识总结(三)

51、启动GNU加速 硬件加速的工作原理 浏览器接收到一个页面之后&#xff0c;将html解析成DOM树&#xff0c;浏览器解析渲染「html」的过程 按着一定的规则执行&#xff0c;DOM树和CSS树结合后构成浏览器形成页面的 渲染树 ; 渲染树中包含大量的渲染元素&#xff0c;每一个元素…

为阿里云服务器ECS实例安装Nodejs

为阿里云服务器ECS实例安装Nodejs部署Node.js项目&#xff08;CentOS&#xff09;准备工作操作步骤步骤1&#xff1a;部署Node.js环境&#xff08;使用二进制文件安装&#xff09;步骤2&#xff1a;部署测试项目部署Node.js项目&#xff08;CentOS&#xff09; 本文档介绍如何…

webstorm激活+汉化教程

1.安装教程激活 输入的激活网址&#xff1a; http://idea.imsxm.com/ 2.汉化教程 软件适用于&#xff1a;webstorm2017.2以及以上&#xff0c;如有需要可直接加本人QQ 1940694428。 转载于:https://www.cnblogs.com/cisum/p/7919712.html

如何从零开始,成为element-plus的contributor

序言 提到element-ui&#xff0c;我想很多前端er应该都不陌生&#xff0c;而element-ui也是我第二个使用的前端UI库&#xff0c;第一个是bootstrap&#xff08;笑&#xff09;。我是在去年初学vue的时候开始接触elemment-ui的&#xff0c;到现在也快一年了&#xff0c;中间经历…