容斥的原理及广义应用

容斥原理

想起容斥原理,大家都不陌生。
相信很多地方都会举这样类似一个最简单的例子让大家理解容斥:
现在赛场上有n个人,都参加过WC、CTSC和APIO。
拿过至少一个比赛的金牌的有多少人?
我们可以简单计算拿过WC金牌的人数+拿过CTSC的金牌的人数+拿过APIO的金牌的人数。
但是这样会记重,比如jasonvictoryan,他既拿过WC的金牌又拿过APIO的金牌,又比如czllgzmzl,他既拿过WC的金牌又拿过CTSC的金牌,这样他们都会被计算两次。
于是我们还要减去同时拿过WC和CTSC的金牌的人数+同时拿过WC和APIO的金牌的人数+同时拿过CTSC和APIO的金牌的人数。
但是这样会记少,比如dwjshift,他WC-CTSC-APIO三金。一开始给他记了3次,然后又减去了他3次,那岂不是没有计算到他。
于是最后再加上同时拿过WC、CTSC和APIO的金牌的人数。
推广到更高的情况,也差不多,符号正负交替。
不知你有没有疑问过,为什么这样在更大的情况下是对的呢?
下面我们来讲讲容斥的原理,懂了这个你对容斥的理解和运气都会更上一层,不再是只会套经典容斥模型的人了!

容斥的原理

我们来思考上面容斥的意义。
比如一个人,他拿到了n个赛事的金牌,那么对于拿过金牌的人这个计数问题的容斥式子下,他会被算多少次?
n=0的时候,他自然是不会被计算到,这符合实际。
n>=1呢?
容易发现是
ni=1Cin(1)i+1
后面那个就是常见的容斥系数。
这个式子的值是多少呢?
我们可以证明这个式子的值为1。
ni=1Cin(1)i+1
= ni=1(Cin1+Ci1n1)(1)i+1
= n1i=1Cin1(1)i+1+ni=1Ci1n1(1)i+1
= n1i=1Cin1(1)i+1+n1i=1Cin1(1)i+2+C0n1
= 1
也就是说一个人只要拿过金牌,他就只会被计算一次!
这就是这个经典容斥问题为什么是对的证明。
而这个思路也就是容斥的原理:
通过对限制的更改使其变成容易计算的计数问题,再通过配以正确的容斥系数,使得最终得到的结果和原问题一致。
什么是配以正确的容斥系数呢?那么就是在设计容斥时,对每个需要计数的情况应该被计数多少次的考虑!
一般容斥问题都是这样:
要满足n个条件:……
而我们只满足或不满足其中一些条件,其余条件不管,然后进行容斥。
这就是把限制更改来变得更容易计算。
比如经典的错排问题:
有多少排列满足ai!=i
我们可以看做有n个条件限制:第i个条件是 ai!=i
不等于是个很大的条件,除了i都能取,而等于是个很严格的条件,直接帮助我们确定了一些位置。
因此错排问题是考虑哪些位置不满足条件,其余位置则随便取。
dp[n]=ni=0(1)iCin(ni)!
dp[n]=ni=0(1)in!i!(ni)!(ni)!
dp[n]=ni=0(1)in!i!
dp[n]=(1)n+n1i=0(1)in!i!
dp[n]=(1)n+nn1i=0(1)i(n1)!i!
dp[n]=(1)n+ndp[n1]

容斥的形式

组合数形式

我们可以给出三种常见的容斥形式,并给出对应例题。
第一种形式是最普遍的,它是
ni=1Cinf(i)
f表示容斥系数。
在一般的问题中,f都表示-1的多少次方。
现在如果把满足至少1个条件改成至少k个条件,可能会有很多人不知道怎么做了。
但如果你明白容斥的原理,你发现就是
ni=1Cinf(i)=[n>=k]
知道这个又怎么样呢?
如果允许n^2的复杂度,你根本不需要去想f是多少,你可以让程序帮你算!
你需要构造这个f来满足式子。
我们考虑让n<=m都满足,那么会确定f的前m项。
现在考虑让n<=m+1都满足,就会将f的第m+1项确定。
这个f一定是存在的,而且是可以推的。
写一个段代码预处理这个f当然不困难。
同样我们可以思考更加丧病的容斥问题:
现在对于每个排列,如果有k个位置满足错排,则价值定义为a[k],求所有排列的价值和。
假如你明白了容斥的原理,你仍然可以用容斥的思路去解决这题,你只需构造f来满足:
ni=1Cinf(i)=a[n]
这样就很方便了!
于是我们现在给一道例题:
这是“玲珑杯”线上赛 Round #17 河南专场某题 。
有n个硬币,初始全部正面朝上。
现在有m次操作,每次把编号是x的倍数的硬币翻面。
最后问多少个硬币正面朝上。
那这个题显然也是容斥题,你先用指数级时间枚举操作,然后求个最小公倍数,接下来问题在于容斥系数怎么定。
有了上面的经验就是构造f满足
ni=1Cinf(i)=ord(n)
这个f用n^2求没有问题。

斯特林数形式

第一种形式的组合数形式,主要是在枚举约束的子集。
而第二种形式,枚举的是划分的子集。
来看下面这道例题:
bzoj异或图
定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与
G2 中的出现次数之和为 1, 那么边 (u, v) 在 G 中, 否则这条边不在 G 中.
现在给定 s 个结点数相同的图 G1…s, 设 S = {G1, G2, … , Gs}, 请问 S 有多少个子集的异
或为一个连通图?

这个题怎么做呢?
容易想到容斥,容斥方向是用贝尔数的时间来枚举子集划分,也就是不同子集一定没有边,同一个子集可以任意。
这样做就很简单,因为我们可以用异或高斯消元解自由元的个数,来得到方案。
但是容斥系数呢?
容易发现这次不是组合数形式了,它应该是
ni=1S(n,i)f(i)
S表示第二类斯特林数,S(n,m)的意义是把n个数划分到m个集合。
这个形式下最普通的容斥系数是 (1)ii!
对于这道题来说容斥系数就是 f(i)=(1)i1(i1)!
我们可以来证明一下这条式子即
nm=1S(n,m)(1)m1(m1)!=[n=1]
证明与组合数形式类似。
n=1显然成立,我们来说明n>=2时它为0。
nm=1S(n,m)(1)m1(m1)!
= nm=1[S(n1,m1)+S(n1,m)m](1)m1(m1)!
= nm=1S(n1,m1)(1)m1(m1)!+n1m=1S(n1,m)(1)m1m!
= n1m=1S(n1,m)(1)mm!+S(n1,0)(1)00!+n1m=1S(n1,m)(1)m1m!
= 0
这就是第二种容斥形式,也可以套容斥系数。

莫比乌斯函数形式

这种容斥其实大家可能见得多了,因为莫比乌斯函数本身就是一种很厉害的容斥系数。
它和组合数意义其实是有点像的。
这种形式一般见于数论问题下,是枚举约数的子集。
我们以phi函数为例。
如何计算n以内和n互质的数的个数呢?
假设n=Πki=1pcii
相当于有k个限制,第i个限制要求不是 pi 的倍数。
于是有这么一条式子
i|nnif(i)
而一般都有 f(i)=μ(i)
我们来考虑一个数会被计算多少次。
显然只有它的因数对它造成影响。
如果这个数是1,因为 μ(1)=1 ,所以它被计算了1次,而1和任意正整数互质。
如果这个数有t个质因子n也有,那么会被计算
ti=1(1)iCit
这其实就是组合数形式那个式子嘛!
所以只会被计算1次。

容斥系数寻找的优化

一般配容斥系数都是痛苦的事情(对于非经典的特殊问题)。
而了解容斥原理后进行容斥系数的构造,可以在n^2复杂度内寻找出容斥系数。
这还不够优秀!

打表法

手算或用程序打表,一般容斥系数都有规律,找到规律后在程序中直接套用,不需要花n^2的复杂度了。
例如翻硬币那个问题,我们可以发现它的容斥系数有规律,是 (1)i2i
这一般是最有效的方法。

反演法

你可以反演,一般来说去套比较麻烦的话可以多项式求逆(雾。
但是常见的容斥形式都是可以记忆如何反演的。
我们来大致讲讲反演吧。
定义 oi,j=[i=j]
定义 fn=ni=1giai,n
它的反演是
gn=ni=1fibi,n
b要满足什么条件?
fn=ni=1giai,n
fn=ni=1ai,nij=1fjbj,i
如果能满足
nk=1ni=1nj=1bj,kak,i=oi,j
上面的式子便可满足。
因此就是这样去构造b。
然后是有二项式反演、斯特林反演这样的东西的。
至于莫比乌斯反演肯定大家都会啊。
这里不进行详细叙述,因为对基本形式反演是有难度的。
组合数形式一般容斥系数会带-1的次幂,其实可以把这个从容斥系数那里拆出来,剩余的可以做二项式反演。
所以就是这样啦!

  • 15
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值