简介

与莫反类似,单位根反演是一个可以表示 [n∣k][n\mid k] 的式子,由此推出的一系列应用:

1n∑i=0n−1ωnki=[n∣k]\frac{1}{n}\sum_{i=0}^{n-1}\omega_n^{ki}=[n\mid k]

当 n∣kn\mid k 时,根据单位根的定义 ωnk=exp⁡(2πikn)=1\omega_n^k=\exp(2\pi i\frac{k}{n})=1,此时原式为 11;当 n∤kn\not\mid k 时根据等比数列求和公式得到:

1n∑i=0n−1(ωnk)i=1n1−ωnnk1−ωnk\frac{1}{n}\sum_{i=0}^{n-1}(\omega_n^k)^i=\frac{1}{n}\frac{1-\omega_n^{nk}}{1-\omega_n^k}

同样根据 ωnnk=exp⁡(2πinkn)=1\omega_n^{nk}=\exp(2\pi i\frac{nk}{n})=1,而 ωnk≠1\omega_n^k\ne 1,因此原式值为 00​。

FFT

回顾 FFT,对于一个 n−1n-1 次的多项式 F(x)F(x),当我们知道 (ωni,F(ωni))(\omega_n^i,F(\omega_n^i)) 时,想根据这个求出所有 [xk]F(x)[x^k]F(x),可以写成这样:

[xk]F(x)=∑j=0n−1[j=k][xj]F(x)=∑j=0n−1[n∣(j−k)][xj]F(x)=∑j=0n−1(1n∑i=0n−1ωn(j−k)i)[xj]F(x)=1n∑j=0n−1∑i=0n−1[xj]F(x)ωn(j−k)i=1n∑j=0n−1∑i=0n−1[xj]F(x)ωnijωn−ki=1n∑i=0n−1F(ωni)ωn−ki=1n∑i=0n−1F(ωni)(ωn−k)i\begin{aligned} \text{[}x^k]F(x)&=\sum_{j=0}^{n-1}[j=k][x^j]F(x)\\ &=\sum_{j=0}^{n-1}[n\mid (j-k)][x^j]F(x)\\ &=\sum_{j=0}^{n-1}\left(\frac{1}{n}\sum_{i=0}^{n-1}\omega_n^{(j-k)i}\right)[x^j]F(x)\\ &=\frac{1}{n}\sum_{j=0}^{n-1}\sum_{i=0}^{n-1}[x^j]F(x)\omega_n^{(j-k)i}\\ &=\frac{1}{n}\sum_{j=0}^{n-1}\sum_{i=0}^{n-1}[x^j]F(x)\omega_n^{ij}\omega_n^{-ki}\\ &=\frac{1}{n}\sum_{i=0}^{n-1}F(\omega_n^i)\omega_{n}^{-ki}\\ &=\frac{1}{n}\sum_{i=0}^{n-1}F(\omega_n^i)(\omega_n^{-k})^i \end{aligned}

也就是 [xk]F(x)[x^k]F(x) 的值是以 F(ωni)F(\omega_n^i) 为 [xi]G(x)[x^i]G(x) 求 G(ωn−k)G(\omega_n^{-k}),而 DFT 的过程就是在求一个多项式在 ωnk\omega_n^k 处的值,因此 IDFT 可以复用 DFT 的代码,只需要把 ωnk\omega_n^k 换成 ωn−k\omega_n^{-k} 最后再乘一下 1n\frac{1}{n} 即可。

用模 pp 的原根 gnk=g(p−1)kng_n^k=g^{(p-1)\frac{k}{n}}​​ 来代替单位根可以避免精度问题。

LJJ 学二项式定理

给定 n,s,a0∼a3n,s,a_0\sim a_3 其中 nn 范围 101810^{18},其它 10810^8。求:

(∑i=0n(ni)siai mod 4) mod 998244353\left(\sum_{i=0}^n\binom{n}{i}s^ia_{i\bmod 4}\right)\bmod 998244353

题目链接:LOJ6485。

考虑枚举 i mod 4=ki\bmod 4=k,而 [i mod 4=k]=[4∣(i−k)][i\bmod 4=k]=[4\mid (i-k)],把同余条件转化为整除条件然后代入单位根反演的式子:

∑i=0n(ni)siai mod 4=∑k=03∑i=0n(ni)siak[i mod 4=k]=∑k=03∑i=0n(ni)siak[4∣(i−k)]=14∑k=03∑j=03∑i=0n(ni)siω4j(i−k)ak=14∑k=03∑j=03(akω4−kj∑i=0n(ni)siω4ji)=14∑k=03∑j=03akω4−kj(sω4j+1)n\begin{aligned} \sum_{i=0}^n\binom{n}{i}s^ia_{i\bmod 4}&=\sum_{k=0}^3\sum_{i=0}^n\binom{n}{i}s^ia_k[i\bmod 4=k]\\ &=\sum_{k=0}^3\sum_{i=0}^n\binom{n}{i}s^ia_k[4\mid (i-k)]\\ &=\frac{1}{4}\sum_{k=0}^3\sum_{j=0}^3\sum_{i=0}^n\binom{n}{i}s^i\omega_4^{j(i-k)}a_k\\ &=\frac{1}{4}\sum_{k=0}^3\sum_{j=0}^3\left(a_k\omega_4^{-kj}\sum_{i=0}^n\binom{n}{i}s^i\omega_4^{ji}\right)\\ &=\frac{1}{4}\sum_{k=0}^3\sum_{j=0}^3a_k\omega_4^{-kj}(s\omega_4^j+1)^n\\ \end{aligned}

单组询问复杂度 O(log⁡n)O(\log n),有 1616 的常数,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <bits/stdc++.h>
using namespace std;

#define int long long
const int P = 998244353, I4 = 748683265;
int T, n, s, a[4];

int qmi(int a, int k) {
int res = 1;
while (k) {
if (k & 1) res = res * a % P;
a = a * a % P;
k >>= 1;
}
return res;
}

signed main() {
cin >> T;
while (T--) {
cin >> n >> s >> a[0] >> a[1] >> a[2] >> a[3];
int res = 0;
for (int k = 0; k < 4; k++) {
int w = qmi(3, (P-1)/4), negwk = qmi(3, P-1-((P-1)/4*k));
for (int j = 0, w1 = 1, w2 = 1; j < 4; j++, w1 = w1 * negwk % P, w2 = w2 * w % P) {
res = (res + a[k] * w1 % P * qmi((s * w2 + 1) % P, n)) % P;
}
}
cout << res * I4 % P << endl;
}
return 0;
}

[洛谷月赛] 小猪佩奇学数学

给定 n,p,kn,p,k 满足 1≤n,p<998244353,k∈{2w∣0≤w≤20}1\le n,p\lt 998244353,k\in\{2^w|0\le w\le 20\} 问:

∑i=0n(ni)pi⌊ik⌋ mod 998244353\sum_{i=0}^n\binom{n}{i}p^i\lfloor\frac{i}{k}\rfloor\bmod 998244353

题目链接:P5591。

根据模的定义,可以将原式子拆成两个部分:

∑i=0n(ni)pi⌊ik⌋=1k∑i=0n(ni)ipi−1k∑i=0n(ni)pi(i mod k)\begin{aligned} \sum_{i=0}^n\binom{n}{i}p^i\lfloor\frac{i}{k}\rfloor&=\frac{1}{k}\sum_{i=0}^n\binom{n}{i}ip^i-\frac{1}{k}\sum_{i=0}^n\binom{n}{i}p^i(i\bmod k) \end{aligned}

对于左半部分,根据组合数的性质有:

1k∑i=0n(ni)ipi=npk∑i=1n(n−1i−1)pi−1=np(p+1)n−1k\frac{1}{k}\sum_{i=0}^n\binom{n}{i}ip^i=\frac{np}{k}\sum_{i=1}^n\binom{n-1}{i-1}p^{i-1}=\frac{np(p+1)^{n-1}}{k}

对于右半部分,同样是枚举 i mod ki\bmod k 的值:

1k∑r=0k−1∑i=0n(ni)pir[i mod k=r]=1k∑r=0k−1∑i=0n(ni)pir[k∣(i−r)]=1k2∑r=0k−1∑i=0n(ni)pir∑j=0k−1ωk(i−r)j=1k2∑r=0k−1∑j=0k−1∑i=0n(ni)pirωkijωk−rj=1k2∑r=0k−1∑j=0k−1rωk−rj∑i=0n(ni)piωkij=1k2∑j=0k−1(pωkj+1)n∑r=0k−1rωk−rj\begin{aligned} \frac{1}{k}\sum_{r=0}^{k-1}\sum_{i=0}^n\binom{n}{i}p^ir[i\bmod k=r]&=\frac{1}{k}\sum_{r=0}^{k-1}\sum_{i=0}^n\binom{n}{i}p^ir[k\mid(i-r)]\\ &=\frac{1}{k^2}\sum_{r=0}^{k-1}\sum_{i=0}^n\binom{n}{i}p^ir\sum_{j=0}^{k-1}\omega_k^{(i-r)j}\\ &=\frac{1}{k^2}\sum_{r=0}^{k-1}\sum_{j=0}^{k-1}\sum_{i=0}^n\binom{n}{i}p^ir\omega_k^{ij}\omega_{k}^{-rj}\\ &=\frac{1}{k^2}\sum_{r=0}^{k-1}\sum_{j=0}^{k-1}r\omega_{k}^{-rj}\sum_{i=0}^n\binom{n}{i}p^i\omega_k^{ij}\\ &=\frac{1}{k^2}\sum_{j=0}^{k-1}(p\omega_k^j+1)^n\sum_{r=0}^{k-1}r\omega_{k}^{-rj}\\ \end{aligned}

对于后边这个等差乘等比,这里推一个结论,错位相减法。

Sn=∑i=1n−1iqiqSn=∑i=2n(i−1)qi(1−q)Sn=−(n−1)qn+∑i=1n−1qiSn=(1−n)qn1−q+q(1−qn−1)(1−q)2=q−qn+(1−q)(1−n)qn(1−q)2=q−nqn+(n−1)qn+1(1−q)2\begin{aligned} S_n&=\sum_{i=1}^{n-1}iq^i\\ qS_n&=\sum_{i=2}^{n}(i-1)q^{i}\\ (1-q)S_n&=-(n-1)q^n+\sum_{i=1}^{n-1}q^i\\ S_n&=\frac{(1-n)q^n}{1-q}+\frac{q(1-q^{n-1})}{(1-q)^2}\\ &=\frac{q-q^n+(1-q)(1-n)q^n}{(1-q)^2}\\ &=\frac{q-nq^n+(n-1)q^{n+1}}{(1-q)^2} \end{aligned}

当然 q=1q=1 时原式等于 n(n−1)2\frac{n(n-1)}{2},这个只能特判。带入得到:

1k2∑j=0k−1(pωkj+1)n∑r=0k−1rωk−rj=1k2∑j=0k−1(pωkj+1)nSk,ωk−j\begin{aligned} \frac{1}{k^2}\sum_{j=0}^{k-1}(p\omega_k^j+1)^n\sum_{r=0}^{k-1}r\omega_{k}^{-rj}&=\frac{1}{k^2}\sum_{j=0}^{k-1}(p\omega_k^j+1)^nS_{k,\omega_k^{-j}} \end{aligned}

懒得根据单位根性质化简 SkS_k 了,反正能 O(1)O(1) 求出来,代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <bits/stdc++.h>
using namespace std;

#define int long long
const int P = 998244353, I2 = 499122177;
int n, p, k;

int qmi(int a, int k = P-2) {
int res = 1;
while (k) {
if (k & 1) res = res * a % P;
a = a * a % P;
k >>= 1;
}
return res;
}

int S(int n, int q) {
if (q == 1) return n * (n-1) % P * I2 % P;
int res = (q - n * qmi(q, n) + (n-1) * qmi(q, n+1)) % P;
res = res * qmi((1-q) * (1-q) % P) % P;
return (res + P) % P;
}

signed main() {
cin >> n >> p >> k;
int r1 = n * p % P * qmi(p+1, n-1) % P * qmi(k) % P;
int r2 = 0;
int wk = qmi(3, (P-1) / k), wkn = qmi(wk);
for (int j = 0, wj = 1, wjn = 1; j < k; j++, wj = wj * wk % P, wjn = wjn * wkn % P) {
r2 = (r2 + qmi((p * wj + 1) % P, n) * S(k, wjn)) % P;
}
int ans = ((r1 - r2 * qmi(k * k % P)) % P + P) % P;
cout << ans << endl;
return 0;
}

[BZOJ3328] PYXFIB

给定 n,k,pn,k,p 其中 n≤1018,k≤2×104,p≤109n\le 10^{18},k\le 2\times 10^4,p\le 10^9 且 pp 为质数,保证 p mod k=1p\bmod k=1,求:

∑i=0⌊nk⌋(nik)fik\sum_{i=0}^{\lfloor\frac{n}{k}\rfloor}\binom{n}{ik}f_{ik}

其中 f0=f1=1f_0=f_1=1,对于 n≥2n\ge 2 有 fn=fn−1+fn−2f_n=f_{n-1}+f_{n-2}。

题目链接:P10664。

首先转化一下,写成单位根反演可以做的式子:

∑i=0n[k∣i](ni)fi=∑i=0n(1k∑j=0k−1ωkij)(ni)fi=1k∑i=0n∑j=0k−1(ni)fiωkij\begin{aligned} \sum_{i=0}^n[k\mid i]\binom{n}{i}f_i&=\sum_{i=0}^n\left(\frac{1}{k}\sum_{j=0}^{k-1}\omega_{k}^{ij}\right)\binom{n}{i}f_i\\ &=\frac{1}{k}\sum_{i=0}^n\sum_{j=0}^{k-1}\binom{n}{i}f_i\omega_{k}^{ij} \end{aligned}

对于斐波那契和组合数乘一块的情况,在 JLCPC2024 C 中也有出现,这里是我写的题解。总之就是由于斐波那契的转移矩阵 AA 和单位阵 EE 具有交换律,因此可以对矩阵用二项式定理。接着推:

1k∑j=0k−1∑i=0n(ni)AiF0ωkij=1k∑j=0k−1∑i=0n(ni)(Aωkj)iEn−iF0=1k∑j=0k−1(Aωkj+E)nF0\begin{aligned} \frac{1}{k}\sum_{j=0}^{k-1}\sum_{i=0}^n\binom{n}{i}A^iF_0\omega_{k}^{ij}&=\frac{1}{k}\sum_{j=0}^{k-1}\sum_{i=0}^n\binom{n}{i}(A\omega_k^j)^iE^{n-i}F_0\\ &=\frac{1}{k}\sum_{j=0}^{k-1}(A\omega_k^j+E)^nF_0 \end{aligned}

这样就可以做到 O(klog⁡n)O(k\log n) 解决了。对于单位根,由于题目保证 p mod k=1p\bmod k=1,因此 ωkj≡gjk(p−1)(modp)\omega_k^j\equiv g^{\frac{j}{k}(p-1)}\pmod p,需要找出来一个原根。这里用原根是为了保证当 k≢0(modφ(p))k\not\equiv 0\pmod{\varphi(p)} 时有 gk≢1(modp)g^k\not\equiv 1\pmod p,否则单位根反演的式子就不成立了。

由于最小原根大概是 O(p14)O(p^{\frac{1}{4}}) 的,原根的充要条件是 δp(g)=φ(p)\delta_p(g)=\varphi(p)。对于任意 gg,由于 δp(g)\delta_p(g) 保证 a0,a1,…,aδp(g)−1a^0,a^1,\dots,a^{\delta_p(g)-1} 互不相同,所以一定有 δp(g)∣φ(p)\delta_p(g)\mid \varphi(p),直接用 φ(p)\varphi(p) 的所有因子 dd 验证是否有 gd≡1(modp)g^d\equiv 1\pmod p 即可。如果存在 d∣φ(p)d\mid \varphi(p) 使得 gd≡1(modp)g^d\equiv 1\pmod p,那么 dd 的倍数一定也满足条件,所以直接枚举 φ(p)/pi\varphi(p)/p_i 即可,其中 pip_i 为 φ(p)\varphi(p) 的质因子。

所以质因数分解 φ(p)\varphi(p),这里的复杂度大概是 O(p)O(\sqrt p)。然后枚举原根,验证的复杂度不计。找到原根后,复杂度为 O(klog⁡n)O(k\log n)。单次复杂度为 O(p+klog⁡n)O(\sqrt p+k\log n),可以通过。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <bits/stdc++.h>
using namespace std;

#define eb emplace_back
#define int long long
int T, n, k, p, g;
vector<int> fac;

int qmi(int a, int k) {
int res = 1;
while (k) {
if (k & 1) res = res * a % p;
a = a * a % p;
k >>= 1;
}
return res;
}

struct Matrix {
int dat[2][2];
Matrix() { memset(dat, 0, sizeof dat); }

Matrix operator*(const Matrix& mat) const {
Matrix res;
for (int i = 0; i < 2; i++)
for (int k = 0; k < 2; k++)
for (int j = 0; j < 2; j++)
res.dat[i][j] = (res.dat[i][j] + dat[i][k] * mat.dat[k][j]) % p;
return res;
}

Matrix qmi(int k) {
Matrix res, a = *this;
res.dat[0][0] = res.dat[1][1] = 1;
while (k) {
if (k & 1) res = res * a;
a = a * a;
k >>= 1;
}
return res;
}
};

signed main() {
cin >> T;
while (T--) {
fac.clear();
cin >> n >> k >> p;
int phi = p-1;
for (int i = 2; i*i <= phi; i++) {
if (phi % i) continue;
while (phi % i == 0) phi /= i;
fac.eb(i);
}
if (phi != 1) fac.eb(phi);

for (g = 2; g < p; g++) {
for (int f: fac) if (qmi(g, (p-1) / f) == 1) goto nxt;
break;
nxt:;
}

int res = 0, w1 = qmi(g, (p-1) / k);
for (int w = 1, j = 0; j < k; j++, w = w * w1 % p) {
Matrix f;
f.dat[0][0] = f.dat[0][1] = f.dat[1][0] = w;
f.dat[0][0]++, f.dat[1][1]++;
// f = A*w+E
f = f.qmi(n);
res = (res + f.dat[0][0]) % p;
}
cout << res * qmi(k, p-2) % p << endl;
}
return 0;
}