[学习笔记] 单位根反演
作者:互联网
引入
单位根反演一般用于求一类 \(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 插值公式具有奇妙的联系,但这和本文主题没有太大关系,因此在这里不做深入展开。不过因为它是实在是很美妙,大概还是会专门开一篇博客讲讲这个东西。
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\)。预处理单位根及其逆元即可做到 \(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;
}
标签:frac,int,sum,单位根,笔记,反演,define,omega,Mod 来源: https://www.cnblogs.com/came11ia/p/16498145.html