[模板]快速傅里叶变换(FFT)
Miskcoo大佬的多项式全家桶传送门
rvalue大佬的FFT讲解传送门
用途
将多项式快速(nlogn)变成点值表达,或将点值表达快速变回系数表达(逆变换),(多数时候)来达到求卷积的目的
做法
(为了方便,用wn代表n次单位根的ωn)
考虑选取特殊点,并用分治缩小问题规模
首先在多项式高位补零使其项数为2的幂,方便分治
然后我们选择代入单位根($w_n^k$),设结果是$y_k$
首先有:$F(x)=\sum{a_ix^i}$
将$a_ix^i$按照幂次奇偶性分组,得到$F(x)=(a_0x^0+a_2x^2+...+a_{n-2}x^{n-2})+(a_1x^1+a_3x^3..a_{n-1}x^{n-1})$
然后设$F_0(x)=a_0x^0+a_2x^1+a_4x^2+...+a_{n-2}x^{\frac{n}{2}-1} $,$F_1(x)=a_1x^0+a_3x^1+a_5x^2+...+a_{n-1}x^{\frac{n}{2}-1}$
则$F(x)=F_0(x^2)+xF_1(x^2)$
于是现在我们将系数完成了分治,但需要代入的值的数量没变所以并没有什么卵用
现在带入n次单位根,$F(w^k_n)=F_0(w^{2k}_n)+w^k_nF_1(w^{2k}_n)$
然后单位根有一个比较喵喵的性质$w^{xk}_{xn}=w^k_n$
于是得到了$F(w^k_n)=F_0(w^k_{\frac{n}{2}})+w^k_nF_1(w^k_{\frac{n}{2}})$
还有一个更喵喵的性质$w^{k}_{n}=-w^{k+\frac{n}{2}}_n$
于是得到了$F(w^{k+\frac{n}{2}}_n)=F_0(w^k_{\frac{n}{2}})-w^k_nF_1(w^k_{\frac{n}{2}}) $
于是成功地完成了对代入的值的分治,可以递归来求了
然而递归太慢了,所以考虑怎么递推来做
(图是偷的)
我们可以从底向上做,将做出来的当前点的结果,用索引值加上这个节点的位置,存在一个大数组中(比如第三层{a2,a6}得出的两个结果存在A[2]和A[3]中,这个索引值可以根据现在在做的长度方便的计算出来)
这样的话,在我们向上推新的一层的时候,设旧一层长度为L,新一层所在节点的第一个编号为i,则有$A[i+k]=A[i+k]+w^k_{2L}A[i+L+k],A[i+k+L]=A[i+k]-w^k_{2L}A[i+L+k] ,k=0..L-1$
然后我们只需要知道最底下一层元素的顺序就可以了
然后观察一下...发现一个很神奇的性质:最后一层第i个元素就对应arev[i],其中rev[i]表示将i的二进制表示翻转后对应的数
| 原位置 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 原位置的二进制表示 | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
| 重排后下标的二进制表示 | 000 | 100 | 010 | 110 | 001 | 101 | 011 | 111 |
| 重排结果 | 0 | 4 | 2 | 6 | 1 | 5 | 3 | 7 |
(表格也是偷的)
所以我们在读入系数后,直接把ai的值给到A[rev[i]]就可以了
于是就得到了点值表达$\{(w^k_n,A[k])\}$
那么现在,只要再根据点值表达推回系数表达就行了
然后经过一系列神奇的推导(我反正不会),我们得到$a_j=\frac{1}{n}\sum_{k=0}^{n-1}y_kw_n^{-kj}$
它的形式和刚刚的定义十分类似,只有$w_n$的指数上多出了个负号,所以我们只要再把刚求出的$y_k$作为系数,把过程中的$w_n^k$改为$w_n^{-k}$,再做一次FFT,然后除以n就是最终结果
快速数论变换(NTT)
有的题要求取模,这时候复数的精度就比较爆炸
考虑在模一类特殊质数($a*2^k+1$,多为998244353)的情况下(任意模数我哪会啊)
可以发现原根(用g表示)和原来单位根的性质非常相似
于是我们用$g^{\frac{P-1}{n}}$代替$w_n$
关于原根怎么求..先记住998244353的原根是3吧233
实现
关于rev的求法:rev[i]=rev[i>>1]>>1|(i&1?(n>>1):0) n是长度
然后对于每个i<rev[i],交换$a_i$和$a_{rev[i]}$ (为了防止交换两次)
可以预处理出所有$w_L^i$(或$g^{\frac{P-1}{L}i}$),记到$g[i]$里(L是一个长度的上界)
然后用的时候,如果要用$w_n^k$,就可以直接用$g[L/n*k]$
随便上一个NTT的代码吧 FFT的效果差不多
inline void fft(int *a,int n,bool flag){
for(int i=;i<n;i++){
rev[i]=(rev[i>>]>>)|((i&)?(n>>):);
if(i<rev[i]) swap(a[i],a[rev[i]]);
}
for(int i=;i<=n;i<<=){
int l=i>>;
for(int j=;j<n;j+=i){
for(int k=;k<l;k++){
int x=a[j+k],y=1ll*g[flag][L/i*k]*a[j+k+l]%P;
a[j+k]=(x+y)%P,a[j+k+l]=(x-y)%P;
}
}
}
if(flag){
int in=fpow(n,P-);
for(int i=;i<n;i++) a[i]=1ll*a[i]*in%P;
}
}
inline void init{
L=<<;
g[][]=g[][]=,g[][]=fpow(,(P-)/L),g[][]=fpow(g[][],P-);
for(int i=;i<L;i++) g[][i]=1ll*g[][i-]*g[][]%P,g[][i]=1ll*g[][i-]*g[][]%P;
}
[模板]快速傅里叶变换(FFT)的更多相关文章
- [模板] 快速傅里叶变换/FFT/NTT
简介 FFT是多项式乘法的一种快速算法, 时间复杂度 \(O(n \log n)\). FFT可以用于求解形如\(C_i = \sum_{j=0}^i A_jB_{i-j}\)的式子. 如果下标有偏差 ...
- 快速傅里叶变换(FFT)_转载
FFTFFT·Fast Fourier TransformationFast Fourier Transformation快速傅立叶变换 P3803 [模板]多项式乘法(FFT) 参考上文 首 ...
- Algorithm: 多项式乘法 Polynomial Multiplication: 快速傅里叶变换 FFT / 快速数论变换 NTT
Intro: 本篇博客将会从朴素乘法讲起,经过分治乘法,到达FFT和NTT 旨在能够让读者(也让自己)充分理解其思想 模板题入口:洛谷 P3803 [模板]多项式乘法(FFT) 朴素乘法 约定:两个多 ...
- 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT)
再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT) 目录 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Blueste ...
- 快速傅里叶变换FFT
多项式乘法 #include <cstdio> #include <cmath> #include <algorithm> #include <cstdlib ...
- [学习笔记] 多项式与快速傅里叶变换(FFT)基础
引入 可能有不少OIer都知道FFT这个神奇的算法, 通过一系列玄学的变化就可以在 $O(nlog(n))$ 的总时间复杂度内计算出两个向量的卷积, 而代码量却非常小. 博主一年半前曾经因COGS的一 ...
- 快速傅里叶变换FFT& 数论变换NTT
相关知识 时间域上的函数f(t)经过傅里叶变换(Fourier Transform)变成频率域上的F(w),也就是用一些不同频率正弦曲线的加 权叠加得到时间域上的信号. \[ F(\omega)=\m ...
- 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/常用套路【入门】
原文链接https://www.cnblogs.com/zhouzhendong/p/Fast-Fourier-Transform.html 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/ ...
- 快速傅里叶变换(FFT)
扯 去北京学习的时候才系统的学习了一下卷积,当时整理了这个笔记的大部分.后来就一直放着忘了写完.直到今天都腊月二十八了,才想起来还有个FFT的笔记没整完呢.整理完这个我就假装今年的任务全都over了吧 ...
随机推荐
- Broadcast发送广播
一.知识介绍 1.[广播分类] ①有序广播:接收者A收到广播传递给B,B传给C,有序传递.任何一个环节都可以终止广播,也可以修改广播中携带的数据. 发送的方式:sendOrderedBroadcast ...
- [伟哥开源项目基金会](https://github.com/AspNetCoreFoundation)
伟哥开源项目基金会 GitHub_base=> 伟哥开源项目基金会 该项目作者为伟哥,GitHub地址:https://github.com/amh1979: 该项目维护者为鸟窝,GitHub地 ...
- python浅拷贝和深拷贝
博文参考地址:https://blog.csdn.net/qq_20084101/article/details/82925067 最近在撸码的时候发现了一个严重的问题: a = [1,2] c = ...
- 浅谈TCP IP协议栈(三)路由器简介
读完这个系列的第一篇浅谈TCP/IP协议栈(一)入门知识和第二篇浅谈TCP/IP协议栈(二)IP地址,在第一篇中,可能我对协议栈中这个栈的解释有问题,栈在数据结构中是一种先进后出的常见结构,而在整个T ...
- Vue项目中的RSA加解密
前后端使用rsa加密: 一般是客户端初始化时访问登录服务时,服务端面动态生成一对RSA对,公钥传给客户端,客户端拿到后,用户输入密码后,点登录时用公钥加密返回给服务端,服务端用私钥解就行了 一.安装 ...
- 浅析foreach语句
本篇是我对于foreach语句(增强for)的总结: 我的总结流程如下: 1.先整体说明增强for遍历集合与数组之间的区别. 2.通过一维数组来说明(给出反编译的源码,形成对照). 3.通过二维数组来 ...
- Java多线程——中断机制
前言:在Java多线程中,中断一直围绕着我们,当我们阅读各种关于Java多线程的资料.书籍时,“中断”一词总是会出现,笔者对其的理解也是朦朦胧胧,因此非常有必要搞清楚Java多线程的中断机制. 1.J ...
- android开发学习 ------- 关于getSupportFragmentManager()不可用的问题
在Android开发中,少不了Fragment的运用. 目前在实际运用中,有v-4包下支持的Fragment以及app包下的Fragment,这两个包下的FragmentManager获取方式有点区别 ...
- MyCP(课下作业,必做)
MyCP(课下作业,必做) 要求 编写MyCP.java 实现类似Linux下cp XXX1 XXX2 的功能,要求MyCP支持两个参数: java MyCP -tx XXX1.txt XXX2.bi ...
- Spring boot整合Mybatis
时隔两个月的再来写博客的感觉怎么样呢,只能用“棒”来形容了.闲话少说,直接入正题,之前的博客中有说过,将spring与mybatis整个后开发会更爽,基于现在springboot已经成为整个业界开发主 ...