NTT Number Theory Transformation

Number theory transformation NTT

Pre-knowledge

  1. FFT: NTT thought and as FFT ( FFT presentation )

    Outline

    Number theory transformation, namely NTT (Number Theory Transformation?), Is based on the FFT domain of number theory, we generally default to FFT fast Fourier transform on the negative domain, and NTT distinction.

We know, using an FFT unit complex roots periodically to \ (\ Theta (N \ log N) \) computational complexity \ (N \) polynomial set value. NTT is actually FFT on the field of number theory, which uses periodic modulo prime number, and FFT reach the same effect.

Primitive root

If \ (A \) mode \ (P \) is equal to the order of \ ([Phi] (P) \) , called \ (A \) modulo \ (P \) is a primitive root (this definition is not important).

For prime \ (P \) , if the \ (G \) is \ (P \) primitive root, then \ (g ^ i \ mod P \) results of pairwise disjoint; or \ (g ^ t = 1 (\ mod P) \) if and only if the index \ (t = P-1 \ ) when established.

We have found that the nature and the original unit of negative root root properties correspond, reciprocity is satisfied and the periodic cycle, and it may be used substituting the interpolation.

NTT

We have a discrete Fourier transform formula

\ [X_k = \ sum ^ {N-1} _ {n = 0} {x_ne ^ {- \ frac {2 \ pi i} {N} nk}} \ \ \ \ \ \ \ \ \ \ \ \ ( k = 0,1, ..., N-1) \]

And inverse transformation formula

\ [X_k = \ frac {1} {N} \ sum ^ {N-1} _ {n = 0} {x_ne '{\ frac {2 \ pi i} {N} nk}} \ \ \ \ \ \ \ \ \ \ \ \ (k = 0,1, ..., N-1) \]

We only need the original root \ (g ^ {\ frac { P-1} {N}} (\ mod P) \) Alternatively Unit complex roots \ (e ^ {- \ frac {-2 \ pi i} {N }} \) , you can get

\ [X_k = \ sum ^ {N-1} _ {n = 0} ^ {nk x_ng {}} (\ mod P) \ \ \ \ \ \ \ \ \ \ \ \ (k = 0,1 ,. .., n-1) \]

with

\ [X_k = \ frac {1} {N} \ sum ^ {N-1} _ {n = 0} {x_ng ^ {- nk}} (\ mod P) \ \ \ \ \ \ \ \ \ \ \ \ (k = 0,1, ..., N-1) \]

achieve

And almost the same FFT template, using the original root \ (g ^ {\ frac { P-1} {N}} (\ mod P) \) Alternatively Unit complex roots \ (e ^ {- \ frac {-2 \ pi i} {N}} \) to

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF=1e9+7,MAXN=3e6+10/*Min:2^20+10*/;
const LL BASE=3,MOD=998244353,INV=332748118;
inline LL fpm(LL base,LL p){
    LL ret=1;
    while(p){
        if(p&1)
            ret=ret*base%MOD;
        base=base*base%MOD;
        p>>=1;
    }
    return ret%MOD;
}
int N,M,limit=1,lg,rev[MAXN];
inline void NTT(LL *a,int type){
    for(int i=0;i<limit;i++)
        if(i<rev[i])
            swap(a[i],a[rev[i]]);
    for(int mid=1;mid<limit;mid<<=1){
        int len=mid<<1/*n*/;
        LL Wn=fpm(type==1?BASE:INV/*BASE^type*/,(MOD-1)/len);
        for(int j=0;j<limit;j+=len){
            LL w=1;
            for(int k=0;k<mid;k++){
                int x=a[j+k],y=w*a[j+k+mid]%MOD;
                a[j+k]=(x+y)%MOD;
                a[j+k+mid]=(x-y+MOD)%MOD;
                w=w*Wn%MOD;
            }
        }
    }
}
LL a[MAXN],b[MAXN];
int main(){
    scanf("%d%d",&N,&M);
    for(int i=0;i<=N;i++){
        scanf("%lld",a+i);
        a[i]=(a[i]+MOD)%MOD;
    }
    for(int i=0;i<=M;i++){
        scanf("%lld",b+i);
        b[i]=(b[i]+MOD)%MOD;
    }
    while(limit<=N+M){
        limit<<=1;
        lg++;
    }
    for(int i=0;i<limit;i++)
        rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));
    NTT(a,1);
    NTT(b,1);
    for(int i=0;i<limit;i++)
        a[i]=a[i]*b[i]%MOD;
    NTT(a,-1);
    LL limit_inv=fpm(limit,MOD-2);
    for(int i=0;i<=N+M;i++)
        printf("%lld ",a[i]*limit_inv%MOD);
    return 0;
}

the complexity

time

And FFT, is \ (\ Theta (N \ log N) \) , fast in the case of smaller data than the FFT, but because there is rapid exponential operation, if the number is too large will result in TLE

space

And FFT, is \ (\ Theta (N) \) , but note that the array size is not \ (N + M \) , but not smaller than \ (N + M \) minimum \ (2 \) of the power

Range (select prime)

We need a large prime number to the modulo this prime number greater than the answer to the final output (but if too large, you need to use rapid multiplication)
Here are a few common prime number, inverse primitive roots and primitive roots

Prime numbers Primitive root Inverse
65537 3 21846
786433 10 235930
5767169 3 1922390
7340033 3 2446678
23068673 3 7689558
104857601 3 34952534
167772161 3 55924054
469762049 3 156587350
998244353 3 332748118
1004535809 3 334845270
2013265921 31 64944062
2281701377 3 760567126
3221225473 5 1932735284
75161927681 3 25053975894
77309411329 7 22088403237
206158430209 22 84337539631
2061584302081 7 589024086309
2748779069441 3 916259689814
6597069766657 5 2638827906663
39582418599937 5 15832967439975
79164837199873 5 47498902319924
263882790666241 7 150790166094995
1231453023109120 3 410484341036374
1337006139375610 3 445668713125206
3799912185593850 5 1519964874237540
4222124650659840 19 888868347507335
7881299347898360 6 1313549891316390
31525197391593400 3 10508399130531100
180143985094819000 6 30023997515803300
1945555039024050000 5 1167333023414430000
4179340454199820000 3 1393113484733270000

Guess you like

Origin www.cnblogs.com/guoshaoyang/p/11276965.html