[学习笔记] 单位根反演

引入

单位根反演一般用于求一类 \(i \bmod k\) 的求和式,通过枚举 \(j \equiv i \pmod{k}\),将式子转化为 \(k\) 次单位根下的操作。这一般要求 \(k \mid (\mathrm{mod} - 1)\)。通常会结合二项式定理使用。

单位根反演

在 FFT 中我们其实已经见过它了:

\[[n\mid k] = \frac{1}{n} \sum_{i=0}^{n-1} \omega_n^{ki} \]

让我们来证明一下:

  • \(k \neq 0 \pmod{n}\) 时,由等比数列求和,右式等于 \(\frac{1}{n} \dfrac{\omega_n^{kn} - 1}{\omega_n^k-1}\),其中 \(\omega_n^k \neq 1\),而 \(\omega_n^{kn} = 1\),因此右式等于 \(0\)

  • \(k \equiv 0 \pmod{n}\) 时,此时 \(\omega_n^{ki} = 1\),等式显然成立。

容易得到如下推论:若 \(p \equiv q \pmod{n}\),即 \(p - q \equiv 0 \pmod{n}\),那么有:

\[[n \mid p-q] = \frac{1}{n} \sum_{i=0}^{n-1} \omega_n^{pi} \omega_n^{-qi} \]

求多项式特定倍数的系数和

\[\sum_{i=0}^{\lfloor \frac{n}{k} \rfloor} [x^{ik}] f(x) = \frac{1}{k} \sum_{j=0}^{k-1} f(\omega_k^j) \]

把多项式大力展开后运用单位根反演容易证明上式。改变求和顺序,上式也可以写成较为简洁的形式:

\[\sum_{k|n} [x^n] f(x) = \frac{1}{k} \sum_{i=0}^{k-1} f(\omega_k^i) \]

事实上上式与 CRT 和 Lagrange 插值公式具有奇妙的联系,但这和本文主题没有太大关系,因此在这里不做深入展开。

不过这个还是写在这里好了,实际上单位根反演指出:

\[[x^0](f(x) \bmod (x^k - 1)) = \frac{1}{k} \sum_{i=0}^{k-1} f(\omega_k^i) \]

简单证明一下,设 \(f(x) = g(x) (x^k-1)+r(x)\),其中 \(g(x)\) 的次数为 \(\deg f - k\)\(r(x)\) 的次数不超过 \(k-1\)

\(f(x) = \sum f_i x^i\)\(g(x) = \sum g_i x^i\),观察 \(g(x)(x^k-1)\)\(g(x)x^k\) 相当于把 \(g(x)\) 的所有系数平移了 \(k\),由于 \(r(x)\) 的次数不超过 \(k-1\),因此对于 \(k \leq i \leq \deg f - k\)\(i\),有 \(g_{i-k} - g_i = f_i\)。特别地,当 \(i > \deg f - k\)\(g_{i-k} = f_i\)。回代容易得到 \(g_0 = \sum_{k|n,1 < n} f_n\),又 \(r_0 - g_0 = f_0\),故 \(r_0 = \sum_{k|n} f_n\),即:

\[[x^0](f(x) \bmod (x^k - 1)) = \sum_{k|n} [x^n] f(x) \]

这就完成了证明。

LOJ 6485 LJJ 学二项式定理

\[\sum_{i=0}^n C_{n}^i s^i a_{i \bmod 4} = \sum_{i=0}^n C_n^i s^i \sum_{j=0}^3 a_j [i \equiv j \ (\mathrm{mod} \ 4)] \]

根据推论,上式可化简为:

\[\begin{aligned} \frac{1}{4} \sum_{i=0}^n C_n^i s^i \sum_{j=0}^3 \sum_{k=0}^3 \omega_4^{ik} \omega_4^{-jk} &= \frac{1}{4} \sum_{j=0}^3 a_j \sum_{k=0}^3 \omega_4^{-jk} \sum_{i=0}^n C_n^i s^i \omega_4^{ik} \\ &= \frac{1}{4} \sum_{j=0}^3 a_j \sum_{k=0}^3 \omega_4^{-jk} (s \omega_4^k +1) ^n \end{aligned} \]

众所周知 \(998244353\) 的原根是 \(3\),因此 \(\omega_4^1 = 3^{\frac{\mathrm{mod} - 1}{4}}\)。预处理单位根及其逆元即可做到 \(O(T \log n)\)

Code
/*
最黯淡的一个 梦最为炽热
万千孤单焰火 让这虚构灵魂鲜活
至少在这一刻 热爱不问为何
存在为将心声响彻
*/
#include <bits/stdc++.h>
#define pii pair<int, int>
#define mp(x, y) make_pair(x, y)
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define int long long
#define mem(x, v, n) memset(x, v, sizeof(int) * (n))
#define mcpy(x, y, n) memcpy(x, y, sizeof(int) * (n))
#define lob lower_bound
#define upb upper_bound
using namespace std;

inline int read() {
	int x = 0, w = 1;char ch = getchar();
	while (ch > '9' || ch < '0') { if (ch == '-')w = -1;ch = getchar(); }
	while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
	return x * w;
}

inline int min(int x, int y) { return x < y ? x : y; }
inline int max(int x, int y) { return x > y ? x : y; }

const int MN = 2e5 + 5;
const int Mod = 998244353;

inline void Pls(int &x, int y) { x += y; if (x >= Mod) x -= Mod; }
inline void Dec(int &x, int y) { x -= y; if (x < 0) x += Mod; }

inline int qPow(int a, int b = Mod - 2, int ret = 1) {
    while (b) {
        if (b & 1) ret = ret * a % Mod;
        a = a * a % Mod, b >>= 1;
    }
    return ret;
}

// #define dbg

int N, s, w[5], iw[5];

inline void Work() {
    N = read(), s = read();
    int ans = 0;
    for (int i = 0; i < 4; i++) {
        int x = read();
        int cur = 1, sig = 0;
        for (int j = 0; j < 4; j++) {
            sig = (sig + cur * qPow(s * w[j] % Mod + 1, N) % Mod) % Mod;
            cur = cur * iw[i] % Mod;
        }
        ans = (ans + x * sig % Mod) % Mod;
    }
    ans = ans * qPow(4) % Mod;
    printf("%lld\n", ans);
}

signed main(void) {
    w[0] = 1;
    w[1] = qPow(3, (Mod - 1) / 4);
    w[2] = w[1] * w[1] % Mod;
    w[3] = w[1] * w[2] % Mod;
    for (int i = 0; i <= 3; i++) iw[i] = qPow(w[i]);

    int T = read();
    while (T--) Work();
    return 0;
}
posted @ 2022-07-20 16:22  came11ia  阅读(209)  评论(0编辑  收藏  举报