笔记:快速傅里叶/数论变换
本文主要讲解
参考了 OI Wiki。
系数表达和点值表达
系数表示法,即由
由
两个多项式相乘,若使用系数表示,复杂度通常为
快速傅里叶变换
思想
点值表示可以很快的进行多项式乘法,通过选取合适的自变量,可以快速将系数表示转化成点值表示,乘法后再快速转回系数表示。
FFT 基于分治思想,通过选取有对称关系的点,可以在
单位复根可以完成这个过程。
过程
对于多项式
单位复根有许多优美的性质,设
由
我们可以用
逆变换
从系数表示到点值表示是一个线性变换的过程:
优化
上述递归过程可以使用非递归实现。
位逆序变换
对
例如
设
蝴蝶变换
在从下往上递推的过程中,由这两个式子:
变换数组中,
通过两个变换,我们不需要申请额外的空间,同时使用了非递归实现,速度更快。
快速数论变换
FFT 存在精度丢失的问题,且不能取模。快速数论变换 NTT 可以解决模意义下的变换。
阶和原根
满足
若
NTT 数论变换
现在假定
常见的质数有
求逆变换时,相似的用
//inv=qpow(Bint(3),p-2);
int rev[N];
void change(Bint f[],int len)
{
for(int i=0;i<len;i++)
{
rev[i]=rev[i>>1]>>1;
if(i&1) rev[i]|=len>>1;
}
for(int i=0;i<len;i++)
if(i<rev[i]) swap(f[i],f[rev[i]]);
}
void ntt(Bint f[],int len,int op)
{
change(f,len);
for(int h=2;h<=len;h<<=1)
{
Bint step=qpow((op==1)?Bint(3):inv,(p-1)/h);
for(int j=0;j<len;j+=h)
{
Bint w(1);
for(int k=j;k<j+h/2;k++)
{
Bint u=f[k],v=w*f[k+h/2];
f[k]=u+v; f[k+h/2]=u-v;
w=w*step;
}
}
}
if(op==-1)
{
Bint iv=qpow(Bint(len),p-2);
for(int i=0;i<len;i++) f[i]=f[i]*iv;
}
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性