AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

NTT学习笔记

作者: 作者的头像   清风qwq ,  2024-01-04 10:37:14 ,  所有人可见 ,  阅读 122


6


1

引入

前置知识:阶与原根

由于 FFT 使用了单位根,导致了精度误差,于是我们考虑用原根代替单位根。

过程和 FFT 是一样的,学过 FFT 的可以跳过,放个 FFT传送门。

取模数 $p = 998244353$,$g=3$($p - 1 = 2^{23}\times 119$)。

设 $g_n = g^{\frac{(p - 1)}{n}}$。


原根的性质

  • $g_n^k = g_n^{k-1} \cdot g_n$
  • $g_n^0 = g_n^n = 1$
  • $g_{2n}^{2k} = g_n^k$
  • $g_n^{\frac{n}{2}} = g^{\frac{p - 1}{2}} = -1$
  • $g_n^{\frac{n}{2} + k} = -g_n^k$

于是发现原根和单位根拥有同样的性质。


快速数论变换

使用 $g_n^k (0\leq k < n)$ 这 $n$ 个不同的数来当作点值表示法中的 $n$ 个 $x$ 。

已知

$$A(x) = \sum_{i=0}^{n-1} a_i * x^i$$

设

$$A_1(x) = a_0 + a_2 \cdot x + a_4 \cdot x^2 + \cdots + a_{n-2} x^{\frac{n}{2}-1}$$

$$A_2(x) = a_1 + a_3 \cdot x + a_5 \cdot x^2 + \cdots + a_{n-1} x^{\frac{n}{2}-1}$$

则

$$A(x) = A_1(x^2) + xA_2(x^2)$$

将 $g_n^k$ 和 $g_n^{\frac{n}{2} + k}(0 \leq k < \frac{n}{2})$ 代入

$$A(g_n^k) = A_1(g_{\frac{n}{2}}^{k}) + g_n^k A_2(g_{\frac{n}{2}}^{k})$$

$$A(g_n^{\frac{n}{2}+k}) = A_1(g_{\frac{n}{2}}^{k}) - g_n^k A_2(g_{\frac{n}{2}}^{k})$$

两个式子 $A_1()$ ,$A_2()$ 相同。

当计算 $[0,\frac{n}{2})$ 时,$[\frac{n}{2},n)$ 可以直接计算。

每次计算量减小一半,时间复杂度 $O(n\log n)$


快速数论逆变换

设 $C(x) = c_0 + c_1 x + c_2 x^2 + \cdots + c_{n - 1} x^{n-1}$

设 $b_i = g_n^i, y_i = C(b_i)$

$C(x)$ 经过 $n$ 个点,$(b_0, y_0) \dots (b_{n - 1}, y_{n - 1}) $


引理1

设

$$S(x) = 1 + x + x^2 + \cdots + x^{n-1}$$

因为

$$S(g_n^k) = g_n^0 + g_n^k + g_n^{2k} + \cdots + g_n^{(n-1)k}$$

又

$$g_n^k S(g_n^k) = g_n^k + g_n^{2k} + \cdots + g_n^{(n-1)k} + g_n^{nk}$$

所以

若 $k\ne 0$

则

$$S(g_n^k) = \frac{0}{1 - g_n^k} = 0$$

若 $k=0$

则

$$S(g_n^k) = n$$


引理2

$$nc_k = \sum_{i=0}^{n-1} y_i (g_n^{-k})^i$$

证明

$$\sum_{i=0}^{n-1} y_i (g_n^{-k})^i$$

$$=\sum_{i=0}^{n-1} (\sum_{j=0}^{n-1} c_j {(g_n^i)}^{j}) (g_n^{-k})^i$$

$$=\sum_{i=0}^{n-1} (\sum_{j=0}^{n-1} c_j {(g_n^j)}^{i}) (g_n^{-k})^i$$

$$=\sum_{i=0}^{n-1} (\sum_{j=0}^{n-1} c_j {(g_n^{j - k})}^{i})$$

$$=\sum_{j=0}^{n-1} c_j \sum_{i=0}^{n-1} (g_n^{j-k})^{i}$$

$$=\sum_{j=0}^{n-1} c_j S(g_n^{j-k})$$

$$=nc_k$$

证毕


设

$$D(x) = \sum_{i=0}^{n-1} y_i x^i$$

则

$$c_k = \frac{D(g_n^{-k})}{n}$$

所以再做一次快速数论变换即可

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 4000010, M = 25, g = 3, gi = 332748118, mod = 998244353;
ll a[N], b[N];

int qpow(int a, int b) {
    int res = 1;
    while (b) {
        if (b & 1) res = 1ll * res * a % mod;
        a = 1ll * a * a % mod;
        b >>= 1;
    }
    return res;
}

struct Poly {
    int rev[1 << M];
    void init(int bit) {
        for (int i = 0; i < (1 << bit); i ++ )
            rev[i] = (rev[i >> 1] >> 1) + ((i & 1) << (bit - 1));
    } void ntt(ll *a, int n, int Inv = 0) {
        for (int i = 0; i < n; i ++ ) if (i < rev[i]) swap(a[i], a[rev[i]]);
        for (int i = 1; i < n; i <<= 1) {
            ll gn = qpow(Inv ? gi : g, (mod - 1) / (i << 1));
            for (int j = 0; j < n; j += (i << 1)) {
                ll gk = 1;
                for (int k = 0; k < i; k ++ , gk = gk * gn % mod) {
                    ll x = a[j + k], y = gk * a[i + j + k] % mod;
                    a[j + k] = (x + y) % mod, a[i + j + k] = (x - y + mod) % mod;
                }
            }
        } if (Inv) {
            ll inv = qpow(n, mod - 2);
            for (int i = 0; i < n; i ++ ) a[i] = a[i] * inv % mod;
        }
    }
} poly;

int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 0; i <= n; i ++ ) scanf("%lld", &a[i]);
    for (int i = 0; i <= m; i ++ ) scanf("%lld", &b[i]);
    int bit = 0;
    while ((1 << bit) <= n + m) bit ++ ;
    poly.init(bit);
    poly.ntt(a, 1 << bit);
    poly.ntt(b, 1 << bit);
    for (int i = 0; i < (1 << bit); i ++ ) a[i] = a[i] * b[i] % mod;
    poly.ntt(a, 1 << bit, 1);
    for (int i = 0; i <= n + m; i ++ ) printf("%lld ", a[i]);
    return 0;
}

1 评论


用户头像
古咩   2024-01-04 10:49         踩      回复

一打开acw就看见柚子厨🥰


App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息