ntt22分(关于原根)
查看原帖
ntt22分(关于原根)
678028
Water_Flower楼主2024/7/23 23:10

对于从点阵到系数阵,即op=-1时(注:我代码中op=1标示系数阵到点阵,op=-1表示点阵到系数阵),原根应改求其倒数(用逆元算),而不是直接乘上 -1
错误示范:

void NNT(long long *f, long long n,long long op){
    for(long long i=0;i<n;++i) if(rev[i] < i) swap(f[i], f[rev[i] ]);
    for(long long mid = 1;mid < n;mid <<= 1){
        long long j = mid << 1; 
        long long gn = (qpow(3, (mod - 1) / j) * op + mod) % mod;//就这一行错了
        for(long long st = 0;st < n; st += j){
            long long g = 1;
            for(long long i = st;i < st + mid; ++i, g =  g * gn % mod){
                long long tmp1 = f[i], tmp2 =  g * f[i + mid] % mod;
                f[i] = (tmp1 + tmp2) % mod;
                f[i + mid] = (tmp1 - tmp2 + mod) % mod;
            }
        }
    }
    if(op == -1){
        long long inv = qpow(n, mod - 2);
        for(long long i = 0; i < n; ++i) f[i] = f[i] * inv % mod;
    }

}

正确示范:

void NTT(long long *f, long long n, long long op){
    for(long long i = 0; i < n; ++i) 
        if(rev[i] < i) swap(f[i], f[rev[i]]);
    
    for(long long mid = 1; mid < n; mid <<= 1){
        long long j = mid << 1; 
        long long gn = qpow(3, (mod - 1) / j);
        if(op == -1) gn = qpow(gn, mod - 2);//应改求其逆元(qpow可以用费马小定理求逆元)
        for(long long st = 0; st < n; st += j){
            long long g = 1;
            for(long long i = st; i < st + mid; ++i, g = g * gn % mod){
                long long tmp1 = f[i], tmp2 = g * f[i + mid] % mod;
                f[i] = (tmp1 + tmp2) % mod;
                f[i + mid] = (tmp1 - tmp2 + mod) % mod;
            }
        }
    }
    if(op == -1){
        long long inv = qpow(n, mod - 2);
        for(long long i = 0; i < n; ++i) f[i] = f[i] * inv % mod;
    }
}
2024/7/23 23:10
加载中...