在这片梦想之地,不堪回首的过去像泡沫一样散去,不愿|

PassName

园龄:3年1个月粉丝:32关注:16

NTT

NTT

1.概念

数论变换由于快速傅里叶变换的提出,大大减少了计算运算次数在有循环卷积特性的条件下,快速数论变换是具有比快速傅里叶更快的快速变换算法。

2.生成子群

子群 : 群 (S,),(S,) , 满足 SS , 则 (S,)(S,) 的子群

3.原根

m 是正整数,a 是整数,若 am 的阶等于 φ(m),则称 a 为模 m 的一个原根。(其中 φ(m) 表示 m 的欧拉函数)

假设一个数 gP 的原根,那么 gi mod P 的结果两两不同,且有 1<g<P0<i<P ,归根到底就是 gP1 = 1 (mod P) 当且仅当指数为 P1 的时候成立.(这里 P 是素数)。

简单来说,gi mod pgj mod pp 为素数),其中 iji, j 介于 1(p1) 之间,则 gp 的原根。

4.NTT 快速数论变化

FFT 利用单位根 ω 的性质实现分治优化多项式乘法,原根也有这样的性质,

NTT 即用原根代替 ω 的 FFT,这样可以不用复数,且实现复数取模运算

对于质数 p=qn+1,(n=2m) , 原根 g 满足 gqn1(mod p)

gn=gp(mod q) , 看作 ωn 的等价。选择二者相似的性质

gnn1(mod p) , gnn21(mod p)

即将 gp1len (mod p) ,看作 ωn=e2πin 的等价 , 即 e2πin gp1len (mod p)

具体实现 : 当合并区间长度为 len=2mid 时,

  • 单位根 ωn=cos2πlen+i sin2πlen=cosπmid+i sinπmid
  • 原根 : gp1len=gp12mid

6.代码 P3803 【模板】多项式乘法(FFT)

#include <bits/stdc++.h>

#define rint register int
#define int long long
#define endl '\n'

using namespace std;

const int N = 5e6 + 5;
const int mod = 998244353;

int n, m, A[N], B[N], lim, r[N];

int qpow(int a, int b) {
    int res = 1 % mod;

    for (; b; b >>= 1) {
        if (b & 1)
            res = 1ll * res * a % mod;

        a = 1ll * a * a % mod;
    }

    return res;
}

void init(int n) {
    int l = -1;

    for (lim = 1; lim < n; lim <<= 1) {
        l++;
    }

    for (rint i = 1; i < lim; i++) {
        r[i] = (r[i >> 1] >> 1) | ((i & 1) << l);
    }

    return ;
}

void NTT(int *x, int inv) {
    int l = 0, res = 0, g = 0; //

    for (rint i = 0; i < lim; ++i) {
        if (i < r[i]) {
            swap(x[i], x[r[i]]);
        }
    }

    for (rint i = 2; i <= lim; i <<= 1) {
        l = i >> 1, res = qpow(inv == 1 ? 3 : 332748118, (mod - 1) / i);

        for (rint *p = x; p != x + lim; p += i) {
            g = 1;

            for (rint j = 0; j < l; ++j) {
                int t = 1ll * g * p[j + l] % mod;
                p[j + l] = (p[j] - t < 0 ? p[j] - t + mod : p[j] - t), p[j] = (p[j] + t > mod ? p[j] + t - mod : p[j] + t);
                g = 1ll * g * res % mod;
            }
        }
    }

    if (inv == -1) {
        int invl = 1ll * qpow(lim, mod - 2);

        for (rint i = 0; i <= lim; ++i) {
            x[i] = 1ll * x[i] * invl % mod;
        }
    }

    return ;
}

signed main() {
    cin >> n >> m;

    init(n + m + 1);

    for (rint i = 0; i <= n; i++) {
        scanf("%d", &A[i]);
    }

    for (rint i = 0; i <= m; i++) {
        scanf("%d", &B[i]);
    }

    NTT(A, 1);
    NTT(B, 1);

    for (rint i = 0; i < lim; i++) {
        A[i] = 1ll * A[i] * B[i] % mod;
    }

    NTT(A, -1);

    for (rint i = 0; i < n + m + 1; i++) {
        printf("%d ", A[i]);
    }

    return 0;
}

本文作者:PassName

本文链接:https://www.cnblogs.com/spaceswalker/p/16523957.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   PassName  阅读(299)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起