容斥原理
概述
-
容斥原理是正难则反思想的实践产物。(23.1.15 upd:存疑)
-
即,在正向求解问题过于困难时,考虑逆向求出不合法方案数,然后用总方案数减去以得到合法方案数。
-
大体上,可以分为以下两类:
子集容斥
-
一般的容斥原理指的就是子集容斥。其是如下的一种容斥:
-
不妨称“合法”为满足
个条件,并抽象为条件的集合,则有如下的一般形式:
-
这里
为满足的条件包含 的方案数。 -
用自然语言描述,就是所有情况(所有条件都爱满足不满足的情况)减去至少有一种条件不满足的加上有两种的减去有三种的...
-
证明基于二项式定理,等等吧...
P1450 [HAOI2008] 硬币购物
-
题意:
-
给出
。 -
组询问,每组询问给出 和 ,求关于 的方程组 的合法解集数。 -
所谓合法解集,即满足
的解集。
-
-
数据范围:
。 -
首先显然可以背包,但也同样的,背包显然会 T。
-
本题有 exgcd 做法,大概思路是预处理
和 两组的 的不定方程,然后对每个询问暴力枚举两组分别付了多少钱,设法 计算方案数。 -
考虑建立容斥模型:所有方案-有一个超限+有两个超限-有三个超限+有四个超限的方案数。
-
则问题相当于怎么求有
个超限的方案数。发现此时的选取个数上界变成了选取个数下界;考虑到这个下界肯定 ,我们用这么一个办法:把它减去! -
即,将
减去 ,于是问题变成完全背包求方案数。 -
发现这个完全背包没有必要每次都做,可以预处理。于是得解,复杂度
。 -
事实上,这一做法可以推广到一般的不定方程非负整数解集计数。
P5664 [CSP-S2019] Emiya 家今天的饭
-
题意略。
-
发现这个主要食材的问题看起来就很状压,但
太大了,全无机会。考虑容斥,即爱超不超-至少一种食材超了+...。 -
发现一种食材如果不合法,其一定占据了至少
道菜,于是同时至多只有一种食材不合法。 -
哦吼!那么容易做一个简单 DP
表示考虑了前 种烹饪方法,是否已经做过菜的总方案数,从而得出满足前两个条件的总方案数。 -
然后再暴力枚举超限的食材,做一个 dp 如下:
-
状态设计:
表示考虑完前 种烹饪方法,做了 道用这个食材的菜,共做了 道菜的方案数。 -
初始化:
。 -
状态转移方程:
。滚维即可。
-
-
总复杂度
,还是超了一些。注意到我们本质上不关心 ,只关心 ,换言之关心的是 。 -
起一个偏移,然后把这两维变成一维,总复杂度
,足够通过本题。
P2158 [SDOI2008] 仪仗队
-
题意:求
。这是转化并舍弃了一点细节后的题意。 -
数据范围:
。 -
式子不是很美妙,考虑拆一拆:
-
首先利用对称性把它化成可欧拉函数化的式子,然后再代入欧拉函数做变换。一开始
是因为漏算 (其他 的在变换中直接被舍弃了),最后 是因为 也计入了并且 了。 -
众所周知,
是可以线性筛的,于是我们有线性复杂度。 -
什么?没容斥?你别急。
P2398 GCD SUM
-
题意:求
。 -
这大概算是一个定式。有两种思路:
-
转化成上面的问题。即:
-
预处理
的前缀和,仍然是线性的。 -
基于调和级数的暴力:
-
考虑求
表示 。此部分的复杂度是 。 -
显然,
就是所有 为 的倍数的数对的数量。考虑容斥之,可以倒序计算, 。 -
但如果我们用一般的容斥原理,那么实质上是对...总之似乎可以用莫反+狄利克雷前缀和优化到
。
P1447 [NOI2010] 能量采集
-
题意略。我们约定
,若不然,交换之。 -
首先从
我们知道这种题目显然可以只做对称的两部分中的一部分。 -
考虑枚举
,不妨记 为 为 的数对数量,稍微化下式子有 。 -
于是问题变成求
。 -
首先我们还是可以进行一个
将其转化到 上,但 不等使得我们的旧有手段失效了,毕竟对称性完全不存在。 -
考虑转而多支付一个
或者之类的。哦,可以容斥! -
套用上面的调和级数方法,得解。
P2567 [SCOI2010] 幸运数字
-
题意略。
-
暴力求出所有幸运号码,然后开始暴搜容斥。
-
几个剪枝技巧:
-
若幸运数字中
,删去 。 -
由此,我们暴搜中的
应当互相不为倍数;从而对于 的可以直接退出,因为任意 至少是 的三倍。
-
P3160 [CQOI2012] 局部极小值
- 参看状压 DP。
代表元容斥
-
子集容斥虽好,但显然有一个致命缺陷:子集总数是指数级的。
-
当条件很多的时候,其根本没有表现的机会。
-
代表元容斥给出了一种解决方法:给条件规定一个“顺序”(这一顺序不能违反条件本身的拓扑关系),按顺序考虑这些条件,从而将所有方案分为“违反了第
个条件的”。 -
换言之,它只关心方案“最早违反的条件”。可以写出如下的一般形式(
为从初始状态到 的合法方案数, 为从 到 的任意方案数):
AT_dp_y Grid 2
-
题意:给出一张
的网格图,有 个点不能经过,求只向下/向右走的条件下(OI 坐标系),从 走到 的方案数。 -
数据范围:
。 -
没有不可经过点的话,这是一个经典的组合数学问题。考虑处理这些点,显然子集容斥根本不可做。
-
注意到对于非法点的访问肯定是有顺序的:
成为代表元,即首个访问的非法点,当且仅当所有 (不能同时取等)的非法点都没有访问时,才有可能。 -
这是一个很松的偏序。随便车一个拓扑序,定义
为从 走到 的合法(这里指路上不经过非法点,起止点不算)方案数, 为对应的任意方案数,于是有:
-
这里所有
都是关键点,即 或非法点。坐标之间的 是以上面的方式定义的,即 ,两个不等号不能同时取等。 -
于是
即为所求,复杂度 。
P2595 [ZJOI2009] 多米诺骨牌
-
题意略。说实话,其他状压和容斥在它面前都黯然失色。
-
首先考虑无限制的情况,即,不考虑跨线只考虑障碍。那么这是一个非常板的轮廓线 dp,我们容易做到
。 -
容易想到把一维用 dp 解决,另一维用容斥。乍一看很对,上面的 dp 也可以加一个
辅助维以确保相邻两行能够横跨,然后呢? -
不妨记
为 列填完,保证合法即每两行之间都有骨牌横跨的方案数。好了,不用说了。 -
我们看到,这里对列之间的横跨容斥的时候,不管是用子集还是用代表元,都有一个问题:左边的方案自己在行间是合法的,右边也一样,但是考虑不到两者本身不合法拼起来合法的方案。
-
考虑进一步以退为进,对两维都容斥!
-
这里我们有所有 dp 值,换言之,我们有
表示子网格 的只考虑障碍不考虑横跨的总方案数。 -
时间复杂度?暴力枚举左上角和右边界,可以对所有下界一口气求出,总复杂度为
,直接跑程序算出复杂度为 ,完全能接受。
-
-
首先肯定不可能都子集容斥,因为时间炸了。考虑使用代表元容斥,我们先给出一个子集容斥套代表元容斥的正解,再谈论其他嵌套方式:
-
暴力枚举哪些列间不合法。这是子集容斥。
-
然后开始代表元容斥,这里我们需要把被分割的多个块合起来考虑行的合法性。
-
定义
表示前 行填完,内部的所有行间都合法的方案数。则有式子为 ,这里 表示第 行随便填(内部行间合法与否无所谓)的方案数,显然其等于各块的 的连乘。 -
我们可以在用到它的时候临时将之算出,带一个
的常数,算 的过程本身显然是 ,故总复杂度为 ,可以接受。
-
-
考虑类似的手法,同时进行两个代表元容斥,外列内行,此时左上两个都满足,右上满足行,左下满足列,右下无限制。注意到主要问题在于此时内层的
(内层小写,外层大写)不再是 的连乘,而是左侧的受列限制的 和右侧的正常 的连乘,先不管这个算一下复杂度,发现是 ,因为外层每枚举一个列间,就需要 种关于行完全合法但关于列随意的 ,而每个 又需要做单独的对行代表元容斥 。 -
回过头来考察内层的
所需的左侧受列限制的 怎么来,事实上只要单独对列容斥就好啦。需要的受列限制的 的 ,其他三维不可知,暴力枚举上下界然后做代表元容斥,显然可以一次把所有右界对应的都求出来, 。乍一看复杂度瓶颈在 dp,所以还是没变,但实际上注意到真的用到无限制 的地方只有内层的“右侧的正常 ”和这里单独对列容斥用到的 ...啊前者确实是顶着右界的,可以只求顶着右界的 ,可惜后者不行。后者还是任意位置的,故复杂度瓶颈确实没变。 -
如果外代表元内子集呢?更劣的一种实现,因为其内部还是需要“左侧的受列限制的
”,某个切割出的块的总方案求法也是左受限 乘右任意 ,其余流程都一样。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】