NTT
好吧,本质上就是FFT,把单位根换成了原根(不是很理解但是就是记住就行)
优点
能取模,FFT的复数你给我来取个模
没有精度差,FFT浮点数的精度怎么也会出一点问题
由于均为整数操作(虽然取模多),NTT常数小,通常比一大堆浮点运算的FFT要快
缺点
多项式的系数都必须是整数
模数有限制,NTT题的模数通常都是相同的998244353
其实这些模数的原根通常都是3
嗯,不太会原根,就不说了
#include<bits/stdc++.h> //NNT
#define Fu(i,a,b) for(register int i=(a);i<=(b);i++)
#define ll long long
#define mod 998244353
using namespace std;
int n,m,len=1,x,rev[8000005],bit,g=3,gi;//g就是所谓原根
ll a[8000005],b[8000005];
int ksm(ll a,int k){
ll ans=1;
while(k){
if(k&1) ans=ans*a%mod;
a=a*a%mod,k>>=1;
}
return ans;
}
void ntt(int n,ll *a,int inv){
Fu(i,0,n) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int mid=1;mid<n;mid<<=1){
ll wn=ksm(inv==1?g:gi,(mod-1)/(mid<<1));
for(int i=0;i<n;i+=mid<<1){
ll w0=1;
Fu(j,0,mid-1){
ll x=a[i+j],y=w0*a[i+j+mid]%mod;
a[i+j]=(x+y)%mod,a[i+j+mid]=(x-y+mod)%mod,w0=w0*wn%mod;
}
}
}
}
int main(){
gi=ksm(g,mod-2);
scanf("%d%d",&n,&m);
Fu(i,0,n) scanf("%lld",&a[i]);
Fu(i,0,m) scanf("%lld",&b[i]);
while(len<=n+m) len<<=1,bit++;
Fu(i,0,len) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
ntt(len,a,1),ntt(len,b,1);
Fu(i,0,len) a[i]=1ll*a[i]*b[i]%mod;
ntt(len,a,-1);
Fu(i,0,n+m) printf("%lld ",a[i]*ksm(len,mod-2)%mod);
return 0;
}
标签:取模,原根,int,FFT,NTT,笔记,学习,模数
From: https://www.cnblogs.com/zhy114514/p/18024042