//写在前面 单就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=<<;
const db pi=.14159265358979323846264338327950288L;
struct cp
{
db a,b;
cp(double a_=,double b_=)
{
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+],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=;while((<<L)!=FFT_MAXN) L++;
for(int i=;i<FFT_MAXN;i++) bitrev[i]=bitrev[i>>]>>|((i&)<<(L-));
for(int i=;i<=FFT_MAXN;i++) nw[i]=cp((db)cosl(*pi/FFT_MAXN*i),(db)sinl(*pi/FFT_MAXN*i));
} // n已保证是2的整数次幂
// flag=1:DFT | flag=-1: IDFT
void dft(cp *a,int n,int flag=)
{
int d=;while((<<d)*n!=FFT_MAXN) d++;
for(int i=;i<n;i++) if(i<(bitrev[i]>>d))
swap(a[i],a[bitrev[i]>>d]);
for(int l=;l<=n;l<<=)
{
int del=FFT_MAXN/l*flag; // 决定 wn是在复平面是顺时针还是逆时针变化,以及变化间距
for(int i=;i<n;i+=l)
{
cp *le=a+i,*ri=a+i+(l>>);
cp *w=flag==? nw:nw+FFT_MAXN; // 确定wn的起点
for(int k=;k<(l>>);k++)
{
cp ne=*ri * *w;
*ri=*le-ne,*le=*le+ne;
le++,ri++,w+=del;
}
}
}
if(flag!=) for(int i=;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=;i<=n+m;i++) c[i]=;
int N=;while(N<=n+m) N<<=; // N是c扩展后的长度
for(int i=;i<N;i++) //扩展 a[],b[] ,存入f[],g[],注意取模
{
LL aa=i<=n?a[i]:,bb=i<=m? b[i]:;
aa%=mod,bb%=mod;
f[i]=cp(db(aa>>),db(aa&));
g[i]=cp(db(bb>>),db(bb&));
}
dft(f,N),dft(g,N);
for(int i=;i<N;i++) // 恢复虚部两个“乘积”(乘积具体意义见上文)
{
int j=i? N-i:;
t[i]=((f[i]+!f[j])*(!g[j]-g[i])+(!f[j]-f[i])*(g[i]+!g[j]))*cp(,0.25);
}
dft(t,N,-);
for(int i=;i<=n+m;i++) upmo(c[i],(LL(t[i].a+0.5))%mod<<);
for(int i=;i<N;i++) // 恢复实部两个“乘积”
{
int j=i? N-i:;
t[i]=(!f[j]-f[i])*(!g[j]-g[i])*cp(-0.25,)+cp(,0.25)*(f[i]+!f[j])*(g[i]+!g[j]);
}
dft(t,N,-);
for(int i=;i<=n+m;i++) upmo(c[i],LL(t[i].a+0.5)+(LL(t[i].b+0.5)%mod<<));
}
}

模板

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

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

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

谢谢阅读

模意义下的FFT算法的更多相关文章

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

    题目链接 首先利用组合数学知识,枚举两人的总胜场数容易得到 这还不是卷积的形式,直接搞的话复杂度大概是O(n^2)的,肯定会TLE.但似乎和卷积有点像?想半天没想出来..多谢Q巨提醒,才知道可以用下面 ...

  2. Newcoder Wannafly13 B Jxy军训(费马小定理、分数在模意义下的值)

    链接:https://www.nowcoder.com/acm/contest/80/B 题目描述 在文某路学车中学高一新生军训中,Jxc正站在太阳下站着军姿,对于这样的酷热的阳光,Jxc 表示非常不 ...

  3. 高斯消元求主元——模意义下的消元cf1155E

    #include <bits/stdc++.h> , MO = ; ; inline int qpow(int a, int b) { ; while(b) { ) { ans = 1ll ...

  4. FFT算法的物理意义

    FFT是离散傅立叶变换的高速算法,能够将一个信号变换到频域.有些信号在时域上是非常难看出什么特征的,可是如果变换到频域之后,就非常easy看出特征了.这就是非常多信号分析採用FFT变换的原因.另外,F ...

  5. FFT算法详解

    啊…本来觉得这是个比较良心的算法没想到这么抽搐这个算法真是将一个人的自学能力锻炼到了极致qwqqwqqwq 好的,那我们就开始我们的飞飞兔FFTFFTFFT算法吧! 偷偷说一句,FFTFFTFFT的代 ...

  6. 基于verilog的FFT算法8点12位硬件实现

    FFT算法8点12位硬件实现 (verilog) 1 一.功能描述: 1 二.设计结构: 2 三.设计模块介绍 3 1.蝶形运算(第一级) 3 2.矢量角度旋转(W) 4 3.CORDIC 结果处理 ...

  7. FFT算法

    FFT算法的完整DSP实现 傅里叶变换或者FFT的理论参考: [1] http://www.dspguide.com/ch12/2.htm The Scientist and Engineer's G ...

  8. msp430学习笔记-实现开方log等计算及FFT算法(待续)

    MSP430 FFT算法实现 http://bbs.21ic.com/icview-391532-1-1.html http://blog.sina.com.cn/s/blog_6cd2030b010 ...

  9. FFT算法的完整DSP实现

    傅里叶变换或者FFT的理论参考: [1] http://www.dspguide.com/ch12/2.htm The Scientist and Engineer's Guide to Digita ...

随机推荐

  1. Leetcode之动态规划(DP)专题-64. 最小路径和(Minimum Path Sum)

    Leetcode之动态规划(DP)专题-64. 最小路径和(Minimum Path Sum) 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小. ...

  2. C#4.0中的协变和逆变

    原文地址 谈谈.Net中的协变和逆变 关于协变和逆变要从面向对象继承说起.继承关系是指子类和父类之间的关系:子类从父类继承所以子类的实例也就是父类的实例.比如说Animal是父类,Dog是从Anima ...

  3. idea自动化部署插件 Alibaba Cloud Toolkit 使用记录

    官方安装文档和使用说明 https://help.aliyun.com/product/29966.html?spm=a2c4g.11186623.6.540.6efa6029JhlPfx 是什么? ...

  4. 课程计划安排 ver: 2016-12-14

    录的越多,后续肯定会涨价. <x86 从实模式到保护模式> 这本书涉及到除了汇编语言,还有一些计算机架构和操作系统方面相关的知识点. 不仅为学习高级编程语言打下了非常扎实的基础,学完C++ ...

  5. 【2019V2全新发布】ComponentOne .NET开发控件集,新增.NET Core数据引擎

    ComponentOne .NET开发控件集 2019V2正式发布,除持续完善并加入全新的.NET开发控件外,还针对产品架构稳定性.易用性.与.NET Core平台深度集成.已有控件功能增强等多个方面 ...

  6. 【一道来自老师的题的题解】equip——奇妙的最短路

    这道题真的第一眼完全想不到是最短路啊!!!!!!!! 感谢DR大佬讲解!!!!!90°鞠躬 =u= 暂时没有评测网址,(因为需要special judge)敬请期待 机房另一大佬JYY题解,可以对比参 ...

  7. 有关最短路上的第k小/大值的总结

    1.USACO08JAN  Telephone Lines 题面 由于问的是最大值最小,所以二分加验证就好了 比较显然的,题干问的是第k+1长的路最短: 那么二分答案是正确的方向: 但是怎么验证? 我 ...

  8. Heavy Transportation POJ 1797 最短路变形

    Heavy Transportation POJ 1797 最短路变形 题意 原题链接 题意大体就是说在一个地图上,有n个城市,编号从1 2 3 ... n,m条路,每条路都有相应的承重能力,然后让你 ...

  9. layui2.5 修改layuicms

    雷哥layui2.5版本学习 学习地址: https://www.bilibili.com/video/av59813890/?p=30 注意: 修改layuicms时注意下面是缓存的js, < ...

  10. Codeforces 1194B. Yet Another Crosses Problem

    传送门 直接枚举填满哪一行,然后看看这一行填满以后哪一列最小 这个预处理一下 $cnt[i]$ 表示初始时第 $i$ 列有几个位置填满就可以做到 $O(m)$ 对于所有情况取个 $min$ 就是答案, ...