快速数论变换(FNTT)
参考资料
思想
快速傅里叶变换(FFT) 在复数域上用单位根 做变换,浮点运算存在精度误差。快速数论变换(Fast Number Theoretic Transform,FNTT)把整个过程搬到模 的整数域上,用 原根(Primitive Root)的幂代替单位根,既精确又天然适合带取模的题目。
要求模数 为 NTT 模数,形如 。设 是模 的原根,则 在模 意义下扮演 次单位根的角色,前提是变换长度 ,即 是 的幂且 。
常用的 NTT 模数及其原根:
| 模数 | 分解 | 原根 |
|---|---|---|
单位根的折半引理、消去引理在原根下同样成立,因此 FFT 的蝶形结构可以原样套用:只需把 换成 ,逆变换时换成它的逆元 ,最后整体乘上 。
实现
using ll=long long;
const int mod=998244353,G=3,Gi=332748118;
void ntt(int *f,int n,int type)
{
for(int i=0;i<n;i++)if(i<r[i])swap(f[i],f[r[i]]);
for(int k=1;k<n;k<<=1)
{
int step=qpow(type==1?G:Gi,(mod-1)/(k<<1));
for(int i=0;i<n;i+=k<<1)
{
int cur=1;
for(int j=0;j<k;j++)
{
int x=f[i+j],y=(ll)cur*f[i+j+k]%mod;
f[i+j]=(x+y)%mod;
f[i+j+k]=(x-y+mod)%mod;
cur=(ll)cur*step%mod;
}
}
}
}
其中 是原根 在模 下的逆元。逆变换后还需将每一项乘以 的逆元。