中文名:快速数论变换。
多项式乘法有时候会建立在模域,对一些特殊的大质数取模时,可以考虑用原根\(g\)来代替,而这些特殊的大质数的原根恰好满足了某些性质,使得多项式乘法在模域中也可以快速的分治合并。
重要定理:(其实只要知道这个就行了)
常见的模数有\(998244353,1004535809,469762049\),这几个数的原根都是\(3(g=3)\)。
代码和FFT挺像的。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &x){
x=0;
static int p;p=1;
static char c;c=getchar();
while(!isdigit(c)){if(c=='-')p=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+(c-48);c=getchar();}
x*=p;
}
const int maxn = 5e6 + 10;
const int mod = 998244353;
int n, m, a[maxn], b[maxn], limit=1, bit;
int rev[maxn];
ll qmi(ll a, ll b)
{
ll res = 1; res %= mod;
while(b)
{
if(b&1) res = (res*a) % mod;
b >>= 1;
a = (a*a)%mod;
} return res%mod;
}
void NTT(int c[], int op)
{
for(int i = 0; i < limit; i++)
if(i < rev[i]) swap(c[i], c[rev[i]]);
for(int mid = 1; mid < limit; mid <<= 1)
{
ll gn = qmi(3, (mod-1)/(mid<<1));
if(op == -1) gn = qmi(gn, mod-2);
for(int j = 0, R = mid<<1; j < limit; j += R)
{
ll g = 1;
for(int k = 0; k < mid; k++, g = (g*gn)%mod)
{
int x = c[j+k], y = g*c[j+k+mid]%mod;
c[j+k] = (x+y)%mod;
c[j+k+mid] = (x-y+mod)%mod;
}
}
}
}
int main()
{
read(n), read(m);
for(int i = 0; i <= n; i++) read(a[i]);
for(int i = 0; i <= m; i++) read(b[i]);
limit = 1;
while(limit <= n+m) limit <<= 1, bit++;
for(int i = 0; i < limit; i++)
rev[i] = (rev[i>>1]>>1)|((i&1)<<(bit-1));
NTT(a, 1); NTT(b, 1);
for(int i = 0; i < limit; i++) a[i] = 1ll*a[i]*b[i]%mod;
NTT(a, -1);
ll inv = qmi(limit, mod-2);
for(int i = 0; i <= n+m; i++)
printf("%d ", (a[i]*inv)%mod);
return 0;
}
原文:https://www.cnblogs.com/zxytxdy/p/12249965.html