容斥原理与各种奇怪反演学习笔记(哈斯图还没画)

容斥原理与各种奇怪反演学习笔记

闲话

发现我这部分学的不咋样,于是来补课。

本文中预计涉及到的内容有:经典容斥原理、莫比乌斯反演(广义和狭义)、子集反演、二项式反演。

容斥原理

引入

我们用一个很简单的数学题来引入对容斥原理的讨论。

120 中,有多少整数既不是 3 的倍数,又不是 5 的倍数?

你当然可以数一遍,但是如果不是 20,而是 101000,那就显然不行了。

小学奥数告诉我们:正难则反是一个很重要的思想。“既不是 3 的倍数,又不是 5 的倍数”不好统计,我们反过来统计“是 3 的倍数,或是 5 的倍数”。

不难发现 3 的倍数共 203=6 个,5 的倍数共 205=4 个,那是不是意味着“是 3 的倍数,或是 5 的倍数”的数有 6+4=10 个呢?并不是,因为 15 既是 3 的倍数,也是 5 的倍数,被算重了,实际上应该是 203+2052015=9 个。然后我们取补集,得到答案为 11

看到这里你已经会了容斥原理,下面来形式化地写一下。

德摩根定律

我们记集合 A 的补集为 A¯,则有如下性质:

  • AB¯=A¯B¯
  • AB¯=A¯B¯
  • Ai¯=Ai¯
  • Ai¯=Ai¯

证明很简单,对前两条讨论一个元素是否在 A 以及 B 中,然后利用前两条推后两条即可。

容斥原理

设集合 Sm 条性质 P1Pm,记 S 中有性质 Pi 的元素为集合 Ai,则集合中至少具有一条性质的元素个数可用下式表达:

|Ai|=|Ai||AiAj|+|AiAjAk|+(1)m+1|Ai|

A={Ai1im},则上式又可以写作:

|Ai|=BA(1)|B|+1|bBb|

证明:

对于 xAi,设 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(11)k=1

证毕。

单点求欧拉 φ 函数

欧拉 φ 函数的定义是 φ(n)=i=1n[gcd(i,n)=1]

n=piai,则由容斥原理有:

φ(n)=nnpi+npipjnpipjpk+±npi=n(11pi)

这就是单点求欧拉函数的原理。

错排问题 Dn

Aii 仍在 i 位置上的全排列集合,则 |Ai|=(n1)!|AiBi|=(n2)!,以此类推。

则答案 Dn 可以写作:

Dn=|Ai¯|=|Ai¯|=n!|Ai|=n!i=1n(1)i+1(ni)(ni)!=n!(1+i=1n(1)i1i!)=n!i=0n(1)ii!

一些简单题

NGM2 的 AC 代码:

// Problem: SP6285 NGM2 - Another Game With Numbers
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/SP6285
// Memory Limit: 1500 MB
// Time Limit: 247 ms
// 
// Powered by CP Editor (https://cpeditor.org)

//By: OIer rui_er
#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 使得 i2n,手玩一下发现容斥系数与 i 的质因子个数有关,就是狭义莫比乌斯 μ 函数,于是线性筛 μ 函数然后整除分块求解即可。

整除分块部分按 n13 分两段分析可知复杂度为 O(n+Tn13)

放一下以前写的 AC 代码:

//By: Luogu@rui_er(122461)
#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):xX,yY}

例如 X={1,2},则 X×X={(1,1),(1,2),(2,1),(2,2)}

前置知识:关系

X 是集合,则关系 RX×X

对于 (a,b)X×X,若 (a,b)R,记作 aRb;否则记作 ab

关系可能有的性质:

  • 自反性:xX,xRx
  • 反自反性:xX,xx
  • 对称性:x,yX,xRyyRx
  • 反对称性:x,yX,xRyyx
  • 传递性:x,y,zX,xRyyRzxRz

前置知识:偏序、偏序集

偏序满足自反性、反对称性、传递性,例如 ,,(记作 )。

集合 X 连通在它上面定义的偏序 为偏序集,记作 (X,)

严格偏序满足反自反性、反对称性、传递性,例如 ,<(记作 )。

对于任意 x,yX,如果满足 xRyyRx,则称 xy 可比,否则不可比。

全序满足 X 的每一对元素在 R 的关系下都可比,例如

前置知识:覆盖、哈斯(Hasse)图

a,bX,如果 ab 且不存在 cX 使得 acb,称 ab 覆盖(或 b 覆盖 a),记作 acb

如果 X 有限,则偏序 由覆盖关系唯一确定。

(X,) 是偏序集,则哈斯(Hasse)图按如下方法生成:

  • 如果 a,bX 满足 ab,将 a 画在 b 下面;如果 ab 覆盖,则在 ab 之间连一条边。

例如偏序集 ({{1,2,3},{1,2},{1,3},{2,3},{1},{2},{3},},) 的哈斯(Hasse)图如下:

【还没画】

卷积

考虑有限偏序集 (X,) 上的二变量函数,设 F(X) 为只要 xy,就有 f(x,y)=0 的所有实值函数的集合,即 X×XR

对于 f,gF,卷积 h=fg

h(x,y)={{z:xzy}f(x,z)g(z,y),xy0,otherwise

易证卷积有结合律 f(gh)=(fg)h(可以展开后通过交换求和顺序证明)。

特殊函数一:克罗内克 δ 函数

δ(x,y)={1,x=y0,xy

即:

δ(x,y)=[x=y]

特殊函数二:ζ 函数

ζ(x,y)={1,xy0,xy

即:

ζ(x,y)=[xy]

逆函数

定义函数 f 的左逆 g 满足 gf=δ

则由卷积定义可知:

δ(x,x)={z:xzx}g(x,z)f(z,x)=g(x,x)f(x,x)

δ(x,x)=[x=x]=1,因此:

g(x,x)=1f(x,x)

下面考虑 xy,由卷积定义可知:

δ(x,y)={z:xzy}g(x,z)f(z,y)

g(x,y)f(y,y) 项移到等号左边:

δ(x,y)g(x,y)f(y,y)={z:xzy}g(x,z)f(z,y)

由于 xy,所以 δ(x,y)=[x=y]=0,因此:

g(x,y)f(y,y)={z:xzy}g(x,z)f(z,y)

恒等变形得:

g(x,y)=1f(y,y){z:xzy}g(x,z)f(z,y)

综上,f 的左逆 g 可表示为:

g(x,y)={1f(x,y),x=y1f(y,y){z:xzy}g(x,z)f(z,y),xy0,otherwise

同理我们定义 f 的右逆 h 满足 fh=δ,显然 g=hg=g(fh)=(gf)h=h),即左逆等于右逆。

特殊函数三:μ 函数

ζ 的逆函数为 μ

考虑 xy,由逆函数定义:

{z:xzy}μ(x,z)ζ(z,y)=δ(x,y)

或等价地,有:

{z:xzy}μ(x,z)=δ(x,y)

因此:

μ(x,y)={1,x=y{z:xzy}μ(x,z),xy0,otherwise

广义莫比乌斯反演公式

(X,) 是偏序集且有最小元素 0μ 是它的莫比乌斯函数,F,G:XRX 上的实值函数,则:

G(x)={z:zx}F(z)F(x)={y:yx}G(y)μ(y,x)

证明如下:

A={y:yx}G(y)μ(y,x)

等量代换得:

A={y:yx}{z:zy}F(z)μ(y,x)

改变 z 枚举范围:

A={y:yx}{z:zX}ζ(z,y)μ(y,x)F(z)

交换求和顺序:

A={z:zX}{y:yx}ζ(z,y)μ(y,x)F(z)

因为 ζ(z,y)=[zy],所以可以改变 y 枚举范围:

A={z:zX}{y:zyx}ζ(z,y)μ(y,x)F(z)

因为 ζμ=δ,等量代换可得:

A={z:zX}δ(z,x)F(z)

因为 δ(z,x)=[z=x],所以得到:

A=F(x)

即:

F(x)={y:yx}G(y)μ(y,x)

另一侧同理。

例子:线性有序集的莫比乌斯函数

X={1,2,n},有偏序集 (X,)

则有:

μ(x,x)=1

考虑 x<y,有:

{z:xzy}μ(x,y)=δ(x,y)

δ(x,y)=[x=y]=0

{z:xzy}μ(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

同理,当 y2μ(x,y)=0

综上:

μ(x,y)={1,y=x1,y=x+10,otherwise

有反演公式:

G(x)=z:zxF(x)F(x)={G(x)G(x1),x2G(0),x=1

也就是前缀和与差分。

广义莫比乌斯反演推论:狭义莫比乌斯反演

提示

【提示】这部分比较抽象,如果你的目标仅仅是做狭义莫比乌斯反演(也就是算法竞赛中常说的莫比乌斯反演)的题目,或者这部分实在看不懂的话,可以选择跳过推导部分,直接去背后面的性质和公式。但是为了逻辑的完整性,我在这里写了狭义莫比乌斯反演的推导过程。

前置知识:偏序集的笛卡尔积(直积)

设偏序集 (X,1)(Y,2),则集合 X×Y 上定义偏序关系

(x,y)(x,y)x1xy2y

易证 (X×Y,) 是偏序集。

推导过程

我们沿用上面的记号,同时记 μ1,μ2,μX,Y,X×Y 的广义莫比乌斯 μ 函数。

可以证明 μ((x,y),(x,y))=μ1(x,x)μ2(y,y)(其中 (x,y),(x,y)X×Y),具体证明过程如下:

如果 xxyy,显然成立。

如果 xx,yy,假设 (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)=xuxμ1(x,u)yvyμ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,) 上的广义莫比乌斯 μ 函数,可以证明,当 ab 时有 μ(a,b)=μ(1,ab),具体证明过程如下:

如果 a=b,显然成立。

如果 a<b,假设 z:az,z<b 都有 μ(a,z)=μ(1,az),记 z=ka,则有:

μ(a,b)=az,zb,zbμ(a,z)=az,zb,zbμ(1,az)=kab,kabμ(1,k)=kba,kbaμ(1,k)=μ(1,ab)

证毕。

现在只需考虑 a=1 的情况。

n=piai,把 n 视为 (Xni={pik:k[0,ai]Z},) 的笛卡尔积中的元素 (p1a1,p2a2,,pkak)

Xni 为线性有序集,我们已经推导过其广义莫比乌斯函数为:

μ(1,piai)={1,ai=01,ai=10,ai2

因此:

μ(1,n)=μ(1,piai)={1,n=1(1)k,i,ai=10,i,ai2

μ(1,n)μ(n),就得到了狭义莫比乌斯函数。

狭义莫比乌斯反演公式

F,GN+ 上的实值函数,则有:

G(n)=knF(k)F(n)=knμ(nk)G(k)

狭义莫比乌斯函数性质和狄利克雷卷积

  • dnμ(d)=[n=1]
  • gcd(p,q)=1,则 μ(pq)=μ(p)μ(q)(积性函数)。
  • n=dnφ(d)

设数论函数 f,g,则它们的狄利克雷卷积为:

(fg)(n)=dnf(d)g(nd)=dnf(nd)g(d)

ϵ(n)=[n=1]I(n)=1id(n)=n,则狄利克雷卷积有如下性质:

  • 满足交换律、结合律、分配律。
  • 积性函数的狄利克雷卷积是积性函数。
  • μI=ϵ
  • φI=id
  • μid=φ

狭义莫比乌斯反演应用

在算法竞赛中,狭义莫比乌斯反演常用于将 ϵ(n) 即艾弗森约定,转化为 dnμ(d),然后调换合适的求和顺序以加速求解。另一个常见用途是狭义莫比乌斯 μ 函数作为容斥系数出现,在前文容斥原理处已经提到。

相关题目见 莫比乌斯反演(函数)练习题单

杜教筛是狄利克雷卷积的一个常见用途,但不是本文要讨论的内容,可能会写一个筛法的学习笔记并放到里面。

广义莫比乌斯反演推论:子集反演

提示

【提示】这部分比较抽象,如果你的目标仅仅是做子集反演的题目,或者这部分实在看不懂的话,可以选择跳过推导部分,直接去背后面的性质和公式。但是为了逻辑的完整性,我在这里写了子集反演的推导过程。

推导过程

接着设 Xn={x:x[1,n]Z},记 P(Xn)={x:xXn}

A,BP(Xn)AB,则 μ(A,B)=(1)|B||A|,证明如下:

如果 A=B,显然成立。

如果 AB,假设 C:ACB 都有 μ(A,C)=(1)|C||A|,设 p=|BA|=|B||A|,则有:

μ(A,B)=C:ACBμ(A,C)=C:ACB(1)|C||A|=k=0p1(1)k(pk)=(1)p(pp)k=0p(1)k(pk)=(1)p(11)p=(1)|B||A|

证毕。

子集反演公式

F,G:P(Xn)R,有反演公式:

G(K)=LKF(L)F(K)=LK(1)|K||L|G(L)

子集反演推论:容斥原理

最开始提到的容斥原理是可以用子集反演来推的。

Ai(iXn)是有限集 S 的子集,对 KXn,定义 F(K)S 中恰好在所有 Ai(iK) 中的元素个数。特别地,F(Xn)=|Ai¯|

G(K)=LKF(L),即 S 中属于所有 Ai(iK) 中的元素个数。特别地,G(Xn)=|S|

因此:

G(K)={|S|,K=Xn|iKAi|,KXn

由子集反演公式:

G(K)=LKF(L)F(K)=LK(1)|K||L|G(L)

K=Xn,则有:

F(Xn)=LXn(1)n|L|G(L)

也就是容斥原理。

子集反演推论:二项式反演

在子集反演公式中:

G(K)=LKF(L)F(K)=LK(1)|K||L|G(L)

F(K)=f(|K|),G(K)=g(|K|),n=|K|,即 F(K),G(K) 仅与 |K| 有关,即得到:

g(n)=i=0n(ni)f(i)f(n)=i=0n(1)ni(ni)g(i)

上式进行变形可以得到二项式反演的另一种形式:

g(n)=i=0n(1)i(ni)f(i)f(n)=i=0n(1)i(ni)g(i)

子集反演、二项式反演应用

这个我还得学学,先咕着。

posted @   rui_er  阅读(259)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示