容斥原理与各种奇怪反演学习笔记
闲话
发现我这部分学的不咋样,于是来补课。
本文中预计涉及到的内容有:经典容斥原理、莫比乌斯反演(广义和狭义)、子集反演、二项式反演。
容斥原理
引入
我们用一个很简单的数学题来引入对容斥原理的讨论。
在 1∼20 中,有多少整数既不是 3 的倍数,又不是 5 的倍数?
你当然可以数一遍,但是如果不是 20,而是 101000,那就显然不行了。
小学奥数告诉我们:正难则反是一个很重要的思想。“既不是 3 的倍数,又不是 5 的倍数”不好统计,我们反过来统计“是 3 的倍数,或是 5 的倍数”。
不难发现 3 的倍数共 ⌊203⌋=6 个,5 的倍数共 ⌊205⌋=4 个,那是不是意味着“是 3 的倍数,或是 5 的倍数”的数有 6+4=10 个呢?并不是,因为 15 既是 3 的倍数,也是 5 的倍数,被算重了,实际上应该是 ⌊203⌋+⌊205⌋−⌊2015⌋=9 个。然后我们取补集,得到答案为 11。
看到这里你已经会了容斥原理,下面来形式化地写一下。
德摩根定律
我们记集合 A 的补集为 ¯¯¯¯A,则有如下性质:
- ¯¯¯¯¯¯¯¯¯¯¯¯¯¯A∪B=¯¯¯¯A∩¯¯¯¯B。
- ¯¯¯¯¯¯¯¯¯¯¯¯¯¯A∩B=¯¯¯¯A∪¯¯¯¯B。
- ¯¯¯¯¯¯¯¯¯¯¯⋃Ai=⋂¯¯¯¯¯¯Ai。
- ¯¯¯¯¯¯¯¯¯¯¯⋂Ai=⋃¯¯¯¯¯¯Ai。
证明很简单,对前两条讨论一个元素是否在 A 以及 B 中,然后利用前两条推后两条即可。
容斥原理
设集合 S 有 m 条性质 P1∼Pm,记 S 中有性质 Pi 的元素为集合 Ai,则集合中至少具有一条性质的元素个数可用下式表达:
∣∣⋃Ai∣∣=∑|Ai|−∑|Ai∩Aj|+∑|Ai∩Aj∩Ak|−⋯+(−1)m+1∣∣⋂Ai∣∣
记 A={Ai∣1≤i≤m},则上式又可以写作:
∣∣⋃Ai∣∣=∑B⊆A(−1)|B|+1∣∣
∣∣⋂b∈Bb∣∣
∣∣
证明:
对于 x∈⋃Ai,设 x 出现在 k 个不同的集合 Ai 中,则 x 在容斥原理中的系数为:
(k1)−(k2)+(k3)−⋯+(−1)k+1(kk)=1−(k0)+(k1)−(k2)+(k3)−⋯+(−1)k+1(kk)=1−((k0)−(k1)+(k2)−(k3)+⋯+(−1)k(kk))=1−(1−1)k=1
证毕。
单点求欧拉 φ 函数
欧拉 φ 函数的定义是 φ(n)=n∑i=1[gcd(i,n)=1]。
设 n=∏piai,则由容斥原理有:
φ(n)=n−∑⌊npi⌋+∑⌊npipj⌋−∑⌊npipjpk⌋+⋯±⌊n∏pi⌋=n∏(1−1pi)
这就是单点求欧拉函数的原理。
错排问题 Dn
记 Ai 为 i 仍在 i 位置上的全排列集合,则 |Ai|=(n−1)!,|Ai∩Bi|=(n−2)!,以此类推。
则答案 Dn 可以写作:
Dn=∣∣⋂¯¯¯¯¯¯Ai∣∣=∣∣∣¯¯¯¯¯¯¯¯¯¯¯¯¯⋃Ai∣∣∣=n!−∣∣⋃Ai∣∣=n!−n∑i=1(−1)i+1(ni)(n−i)!=n!(1+n∑i=1(−1)i1i!)=n!n∑i=0(−1)ii!
一些简单题
NGM2 的 AC 代码:
#include <bits/stdc++.h>
#define rep(x,y,z) for(ll x=(y);x<=(z);x++)
#define per(x,y,z) for(ll x=(y);x>=(z);x--)
#define debug printf("Running %s on line %d...\n",__FUNCTION__,__LINE__)
#define fileIO(s) do{freopen(s".in","r",stdin);freopen(s".out","w",stdout);}while(false)
using namespace std;
typedef long long ll;
const ll N = 20;
ll n, k, a[N], ans;
template<typename T> void chkmin(T& x, T y) {if(x > y) x = y;}
template<typename T> void chkmax(T& x, T y) {if(x < y) x = y;}
int main() {
scanf("%lld%lld", &n, &k);
rep(i, 0, k-1) scanf("%lld", &a[i]);
rep(sta, 0, (1LL<<k)-1) {
ll now = 1;
rep(i, 0, k-1) {
if((sta >> i) & 1) {
now /= __gcd(now, a[i]);
now *= a[i];
if(now > n) break;
}
}
ll mult = (__builtin_popcountll(sta) & 1) ? -1 : 1;
ans += mult * (n / now);
}
printf("%lld\n", ans);
return 0;
}
容斥系数为狭义莫比乌斯 μ 函数的题
其实也就是容斥原理的应用,只不过系数比较有特点。
以 SQFREE 为例,尝试枚举因子 i 使得 i2∣n,手玩一下发现容斥系数与 i 的质因子个数有关,就是狭义莫比乌斯 μ 函数,于是线性筛 μ 函数然后整除分块求解即可。
整除分块部分按 n13 分两段分析可知复杂度为 O(√n+T⋅n13)。
放一下以前写的 AC 代码:
#include <bits/stdc++.h>
#define rep(x,y,z) for(ll x=y;x<=z;x++)
#define per(x,y,z) for(ll x=y;x>=z;x--)
#define debug printf("Running %s on line %d...\n",__FUNCTION__,__LINE__)
#define fileIO(s) do{freopen(s".in","r",stdin);freopen(s".out","w",stdout);}while(false)
using namespace std;
typedef long long ll;
const ll N = 1e7+5;
ll T, n, tab[N], p[N], tot, mu[N], s[N];
template<typename T> void chkmin(T& x, T y) {if(x > y) x = y;}
template<typename T> void chkmax(T& x, T y) {if(x < y) x = y;}
void sieve(ll lim) {
mu[1] = 1;
rep(i, 2, lim) {
if(!tab[i]) {
p[++tot] = i;
mu[i] = -1;
}
for(ll j=1;j<=tot&&i*p[j]<=lim;j++) {
tab[i*p[j]] = 1;
if(i % p[j]) mu[i*p[j]] = -mu[i];
else break;
}
}
rep(i, 1, lim) s[i] = s[i-1] + mu[i];
}
int main() {
sieve(10000000);
for(scanf("%lld", &T);T;T--) {
scanf("%lld", &n);
ll ans = 0, lim = sqrt(n);
for(ll L=1,R=0;L<=lim;L=R+1) {
R = min((ll)sqrt(n/(n/(L*L))), lim);
ans += (s[R] - s[L-1]) * (n / (L * L));
}
printf("%lld\n", ans);
}
return 0;
}
广义莫比乌斯反演
提示
【提示】这部分比较抽象,如果你的目标仅仅是做狭义莫比乌斯反演(也就是算法竞赛中常说的莫比乌斯反演)、子集反演、二项式反演的题目,或者这部分实在看不懂的话,可以选择跳过广义莫比乌斯反演部分,直接去背后面部分的公式。但是为了逻辑的完整性,我在这里写了广义莫比乌斯反演的内容。
前置知识:集合的笛卡尔积(直积)
X,Y 是集合,则 X×Y={(x,y):x∈X,y∈Y}。
例如 X={1,2},则 X×X={(1,1),(1,2),(2,1),(2,2)}。
前置知识:关系
X 是集合,则关系 R⊆X×X。
对于 (a,b)∈X×X,若 (a,b)∈R,记作 aRb;否则记作 aR/b。
关系可能有的性质:
- 自反性:∀x∈X,xRx。
- 反自反性:∀x∈X,xR/x。
- 对称性:∀x,y∈X,xRy⟹yRx。
- 反对称性:∀x,y∈X,xRy⟹yR/x。
- 传递性:∀x,y,z∈X,xRy∧yRz⟹xRz。
前置知识:偏序、偏序集
偏序满足自反性、反对称性、传递性,例如 ⊆,⩽,∣(记作 ≼)。
集合 X 连通在它上面定义的偏序 ≼ 为偏序集,记作 (X,≼)。
严格偏序满足反自反性、反对称性、传递性,例如 ⫋,<(记作 ≺)。
对于任意 x,y∈X,如果满足 xRy 或 yRx,则称 x 和 y 可比,否则不可比。
全序满足 X 的每一对元素在 R 的关系下都可比,例如 ⩽。
前置知识:覆盖、哈斯(Hasse)图
设 a,b∈X,如果 a≺b 且不存在 c∈X 使得 a≺c≺b,称 a 被 b 覆盖(或 b 覆盖 a),记作 a≺cb。
如果 X 有限,则偏序 ≼ 由覆盖关系唯一确定。
设 (X,≼) 是偏序集,则哈斯(Hasse)图按如下方法生成:
- 如果 a,b∈X 满足 a≼b,将 a 画在 b 下面;如果 a 被 b 覆盖,则在 a 和 b 之间连一条边。
例如偏序集 ({{1,2,3},{1,2},{1,3},{2,3},{1},{2},{3},∅},⊆) 的哈斯(Hasse)图如下:
【还没画】
卷积
考虑有限偏序集 (X,≼) 上的二变量函数,设 F(X) 为只要 x⋠y,就有 f(x,y)=0 的所有实值函数的集合,即 X×X→R。
对于 f,g∈F,卷积 h=f∗g 为
h(x,y)={∑{z:x≼z≼y}f(x,z)g(z,y),x≼y0,otherwise
易证卷积有结合律 f∗(g∗h)=(f∗g)∗h(可以展开后通过交换求和顺序证明)。
特殊函数一:克罗内克 δ 函数
δ(x,y)={1,x=y0,x≠y
即:
δ(x,y)=[x=y]
特殊函数二:ζ 函数
ζ(x,y)={1,x≼y0,x⋠y
即:
ζ(x,y)=[x≼y]
逆函数
定义函数 f 的左逆 g 满足 g∗f=δ。
则由卷积定义可知:
δ(x,x)=∑{z:x≼z≼x}g(x,z)f(z,x)=g(x,x)f(x,x)
而 δ(x,x)=[x=x]=1,因此:
g(x,x)=1f(x,x)
下面考虑 x≺y,由卷积定义可知:
δ(x,y)=∑{z:x≼z≼y}g(x,z)f(z,y)
把 g(x,y)f(y,y) 项移到等号左边:
δ(x,y)−g(x,y)f(y,y)=∑{z:x≼z≺y}g(x,z)f(z,y)
由于 x≺y,所以 δ(x,y)=[x=y]=0,因此:
−g(x,y)f(y,y)=∑{z:x≼z≺y}g(x,z)f(z,y)
恒等变形得:
g(x,y)=−1f(y,y)∑{z:x≼z≺y}g(x,z)f(z,y)
综上,f 的左逆 g 可表示为:
g(x,y)=⎧⎪
⎪
⎪⎨⎪
⎪
⎪⎩1f(x,y),x=y−1f(y,y)∑{z:x≼z≺y}g(x,z)f(z,y),x≺y0,otherwise
同理我们定义 f 的右逆 h 满足 f∗h=δ,显然 g=h(g=g∗(f∗h)=(g∗f)∗h=h),即左逆等于右逆。
特殊函数三:μ 函数
ζ 的逆函数为 μ。
考虑 x≼y,由逆函数定义:
∑{z:x≼z≼y}μ(x,z)ζ(z,y)=δ(x,y)
或等价地,有:
∑{z:x≼z≼y}μ(x,z)=δ(x,y)
因此:
μ(x,y)=⎧⎪
⎪⎨⎪
⎪⎩1,x=y−∑{z:x≼z≺y}μ(x,z),x≺y0,otherwise
广义莫比乌斯反演公式
设 (X,≼) 是偏序集且有最小元素 0,μ 是它的莫比乌斯函数,F,G:X→R 是 X 上的实值函数,则:
G(x)=∑{z:z≼x}F(z)⟺F(x)=∑{y:y≼x}G(y)μ(y,x)
证明如下:
设 A=∑{y:y≼x}G(y)μ(y,x)。
等量代换得:
A=∑{y:y≼x}∑{z:z≼y}F(z)μ(y,x)
改变 z 枚举范围:
A=∑{y:y≼x}∑{z:z∈X}ζ(z,y)μ(y,x)F(z)
交换求和顺序:
A=∑{z:z∈X}∑{y:y≼x}ζ(z,y)μ(y,x)F(z)
因为 ζ(z,y)=[z≼y],所以可以改变 y 枚举范围:
A=∑{z:z∈X}∑{y:z≼y≼x}ζ(z,y)μ(y,x)F(z)
因为 ζ∗μ=δ,等量代换可得:
A=∑{z:z∈X}δ(z,x)F(z)
因为 δ(z,x)=[z=x],所以得到:
A=F(x)
即:
F(x)=∑{y:y≼x}G(y)μ(y,x)
另一侧同理。
例子:线性有序集的莫比乌斯函数
设 X={1,2⋯,n},有偏序集 (X,⩽)。
则有:
μ(x,x)=1
考虑 x<y,有:
∑{z:x⩽z⩽y}μ(x,y)=δ(x,y)
而 δ(x,y)=[x=y]=0:
∑{z:x⩽z⩽y}μ(x,y)=0
令 y=x+1,得:
μ(x,x)+μ(x,x+1)=0
又因为 μ(x,x)=1,所以:
μ(x,x+1)=−1
令 y=x+2,同理得:
μ(x,x)+μ(x,x+1)+μ(x,x+2)=0
等量代换得:
μ(x,x+2)=0
同理,当 y⩾2 时 μ(x,y)=0。
综上:
μ(x,y)=⎧⎨⎩1,y=x−1,y=x+10,otherwise
有反演公式:
G(x)=∑z:z⩽xF(x)⟺F(x)={G(x)−G(x−1),x⩾2G(0),x=1
也就是前缀和与差分。
广义莫比乌斯反演推论:狭义莫比乌斯反演
提示
【提示】这部分比较抽象,如果你的目标仅仅是做狭义莫比乌斯反演(也就是算法竞赛中常说的莫比乌斯反演)的题目,或者这部分实在看不懂的话,可以选择跳过推导部分,直接去背后面的性质和公式。但是为了逻辑的完整性,我在这里写了狭义莫比乌斯反演的推导过程。
前置知识:偏序集的笛卡尔积(直积)
设偏序集 (X,≼1) 和 (Y,≼2),则集合 X×Y 上定义偏序关系 ≼:
(x,y)≼(x′,y′)⟺x≼1x′∧y≼2y′
易证 (X×Y,≼) 是偏序集。
推导过程
我们沿用上面的记号,同时记 μ1,μ2,μ 为 X,Y,X×Y 的广义莫比乌斯 μ 函数。
可以证明 μ((x,y),(x′,y′))=μ1(x,x′)μ2(y,y′)(其中 (x,y),(x′,y′)∈X×Y),具体证明过程如下:
如果 x⊀x′ 或 y⊀y′,显然成立。
如果 x≺x′,y≺y′,假设 ∀(u,v):(x,y)≼(u,v)≺(x′,y′) 都有 μ((x,y),(u,v))=μ1(x,u)μ2(y,v),则有:
μ((x,y),(x′,y′))=−∑(x,y)≼(u,v)≺(x′,y′)μ((x,y),(u,v))=−∑(x,y)≼(u,v)≺(x′,y′)μ1(x,u)μ2(y,v)=−∑(x,y)≼(u,v)≼(x′,y′)μ1(x,u)μ2(y,v)+μ1(x,x′)μ2(y,y′)=−∑x≼u≼x′μ1(x,u)∑y≼v≼y′μ2(y,v)+μ1(x,x′)μ2(y,y′)=0+μ1(x,x′)μ2(y,y′)=μ1(x,x′)μ2(y,y′)
证毕。
设 Xn={x:x∈[1,n]∩Z},考虑偏序集 Dn=(Xn,∣) 上的广义莫比乌斯 μ 函数,可以证明,当 a∣b 时有 μ(a,b)=μ(1,ab),具体证明过程如下:
如果 a=b,显然成立。
如果 a<b,假设 ∀z:a∣z,z<b 都有 μ(a,z)=μ(1,az),记 z=ka,则有:
μ(a,b)=−∑a∣z,z∣b,z≠bμ(a,z)=−∑a∣z,z∣b,z≠bμ(1,az)=−∑ka∣b,ka≠bμ(1,k)=−∑k∣ba,k≠baμ(1,k)=μ(1,ab)
证毕。
现在只需考虑 a=1 的情况。
设 n=∏piai,把 n 视为 (Xin={pki:k∈[0,ai]∩Z},∣) 的笛卡尔积中的元素 (pa11,pa22,⋯,pakk)。
Xin 为线性有序集,我们已经推导过其广义莫比乌斯函数为:
μ(1,paii)=⎧⎨⎩1,ai=0−1,ai=10,ai⩾2
因此:
μ(1,n)=∏μ(1,paii)=⎧⎪⎨⎪⎩1,n=1(−1)k,∀i,ai=10,∃i,ai⩾2
记 μ(1,n) 为 μ(n),就得到了狭义莫比乌斯函数。
狭义莫比乌斯反演公式
设 F,G 为 N+ 上的实值函数,则有:
G(n)=∑k∣nF(k)⟺F(n)=∑k∣nμ(nk)G(k)
狭义莫比乌斯函数性质和狄利克雷卷积
- ∑d∣nμ(d)=[n=1]。
- 若 gcd(p,q)=1,则 μ(pq)=μ(p)μ(q)(积性函数)。
- n=∑d∣nφ(d)。
设数论函数 f,g,则它们的狄利克雷卷积为:
(f∗g)(n)=∑d∣nf(d)g(nd)=∑d∣nf(nd)g(d)
设 ϵ(n)=[n=1],I(n)=1,id(n)=n,则狄利克雷卷积有如下性质:
- 满足交换律、结合律、分配律。
- 积性函数的狄利克雷卷积是积性函数。
- μ∗I=ϵ。
- φ∗I=id。
- μ∗id=φ。
狭义莫比乌斯反演应用
在算法竞赛中,狭义莫比乌斯反演常用于将 ϵ(n) 即艾弗森约定,转化为 ∑d∣nμ(d),然后调换合适的求和顺序以加速求解。另一个常见用途是狭义莫比乌斯 μ 函数作为容斥系数出现,在前文容斥原理处已经提到。
相关题目见 莫比乌斯反演(函数)练习题单。
杜教筛是狄利克雷卷积的一个常见用途,但不是本文要讨论的内容,可能会写一个筛法的学习笔记并放到里面。
广义莫比乌斯反演推论:子集反演
提示
【提示】这部分比较抽象,如果你的目标仅仅是做子集反演的题目,或者这部分实在看不懂的话,可以选择跳过推导部分,直接去背后面的性质和公式。但是为了逻辑的完整性,我在这里写了子集反演的推导过程。
推导过程
接着设 Xn={x:x∈[1,n]∩Z},记 P(Xn)={x:x⊆Xn}。
设 A,B∈P(Xn) 且 A⊆B,则 μ(A,B)=(−1)|B|−|A|,证明如下:
如果 A=B,显然成立。
如果 A⫋B,假设 ∀C:A⊆C⫋B 都有 μ(A,C)=(−1)|C|−|A|,设 p=|B∖A|=|B|−|A|,则有:
μ(A,B)=−∑C:A⊆C⫋Bμ(A,C)=−∑C:A⊆C⫋B(−1)|C|−|A|=−p−1∑k=0(−1)k(pk)=(−1)p(pp)−p∑k=0(−1)k(pk)=(−1)p−(1−1)p=(−1)|B|−|A|
证毕。
子集反演公式
设 F,G:P(Xn)→R,有反演公式:
G(K)=∑L⊆KF(L)⟺F(K)=∑L⊆K(−1)|K|−|L|G(L)
子集反演推论:容斥原理
最开始提到的容斥原理是可以用子集反演来推的。
设 Ai(i∈Xn)是有限集 S 的子集,对 K⊆Xn,定义 F(K) 为 S 中恰好在所有 Ai(i∉K) 中的元素个数。特别地,F(Xn)=∣∣⋂¯¯¯¯¯¯Ai∣∣。
记 G(K)=∑L⊆KF(L),即 S 中属于所有 Ai(i∉K) 中的元素个数。特别地,G(Xn)=|S|。
因此:
G(K)=⎧⎪
⎪⎨⎪
⎪⎩|S|,K=Xn∣∣
∣∣⋂i∉KAi∣∣
∣∣,K≠Xn
由子集反演公式:
G(K)=∑L⊆KF(L)⟺F(K)=∑L⊆K(−1)|K|−|L|G(L)
令 K=Xn,则有:
F(Xn)=∑L⊆Xn(−1)n−|L|G(L)
也就是容斥原理。
子集反演推论:二项式反演
在子集反演公式中:
G(K)=∑L⊆KF(L)⟺F(K)=∑L⊆K(−1)|K|−|L|G(L)
设 F(K)=f(|K|),G(K)=g(|K|),n=|K|,即 F(K),G(K) 仅与 |K| 有关,即得到:
g(n)=n∑i=0(ni)f(i)⟺f(n)=n∑i=0(−1)n−i(ni)g(i)
上式进行变形可以得到二项式反演的另一种形式:
g(n)=n∑i=0(−1)i(ni)f(i)⟺f(n)=n∑i=0(−1)i(ni)g(i)
子集反演、二项式反演应用
这个我还得学学,先咕着。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现