全集 种有若干元素,每个元素 都有若干个不同的属性 .令 为满足第 个属性的集合。现有 个元素, 个属性,欲求 ,记 即不满足第 个属性的元素构成的集合。
艾弗森记号是有力的工具。
这就得到了计数问题中容斥原理的常见形式,考虑其组合意义:
计数问题中,全集即为所有方案构成的集合。
意思是,这 种限制全部满足的方案数是多少。
的意思是,枚举了一个集合 ,强行钦定这些限制是不满足的,其余的任意,一共有多少方案。将其乘上其容斥系数 再求和即为所求方案数。
另一方向的也类似:
注意: 当 的时候应为 .
而在一类通过容斥和 dp 解决的问题中,会选择直接带着容斥系数 dp 方案数。且看例题:
「CSP-S 2019」Emiya 家今天的饭
就这也叫容斥?
第三个限制很愤怒,先不管它,算出所有的方案,再容斥掉不合法的,然后就会发现,只需要一层容斥就可以了。
具体地,枚举哪个主要食材是超了的,在这上面做个 dp,以 表示考虑了前 个烹饪方法,一共烹饪了 个菜,而且已经用食材 烹饪了 个菜,方案数是多少。为了能够转移 ,还需要预处理出每一行的 之和。这样时间复杂度是 .
但是注意到最终统计答案的时候只关心 是否大于等于 ,所以令 为考虑前 个烹饪方法,用食材 烹饪的菜的个数,减去不用食材 的菜的个数为 ,方案数是多少。这样复杂度就降到了 .Code.
ARC096E Everything on It
考虑将第二个容斥掉,枚举有 出现次数 次,剩余的无限制,假设其方案为 .
那么答案就是 .
考虑 怎么算,令 ,首先考虑不包含 的子集一共有 个,然后再考虑包含 的子集,相当于将 分成若干个不同的集合,每个集合从 个集合中找一个集合,与其的并集构成一个新的集合。
令 为将 分成若 个不同的集合的方案数(第二类斯特林数),枚举有 中出现了的有 个,一共分成 个集合,那么就有:
考虑后面那个求和号的组合意义,就是从 个元素中选出 个元素,再将这 个元素划分成 个集合。如果把没有选出的元素也看成一个集合,那么其就是 个元素划分成 个集合,其中有一个集合有标号且可空。所以:
要注意 计算时要将指数模 .
Code.
「ZJOI2016」小星星
现在有大小均为 的图 和树 ,求符合条件的排列 的个数,满足若 ,则 .
比较容易理解的容斥,但并不是很容易想到要用容斥,要将什么条件容斥掉。
考虑一个暴力 dp, 考虑了 中考虑 的子树,点 映射到了图中的点 ,已经被映射到的点集是 .
暴力 dp 是 ,考虑到它的第三维是个子集卷积,难以优化,需要想办法规避掉子集卷积。
回想一下为什么要记录 ,在 dp 过程中可以枚举当前点映射到了哪个点,这样已经满足 中每个点映射到了 中的一个点,为了要满足映射到的点两两不同,即 中的点都被映射到,所以需要记录 .
那么就将这个容斥掉,枚举 中一个集合 ,钦定这个 中的点没有被映射到,方案数乘上容斥系数 求和即为答案。
枚举 后,没有了“映射到的点两两不同”这个限制,于是乎可以直接 为考虑子树 ,且点 映射到了 的方案数,容易做到总时间复杂度 dp.总的复杂度就是 .
虽然最终答案不会爆 long long
,但是中间的 dp 可能会爆 long long
,可以用 unsigned long long
直接自然溢出啥事没有,用 long long
的溢出似乎也能过,但是其实是 UB.Code.
「2021 山东三轮集训 Day2」体育测试
给定序列 ,求合法排列 的方案数使得:
- ,则满足 在 中出现位置 ;
- ,则满足 在 中出现位置 .
,模 .
首先考虑如果只有 ,将 从小到大排序,那么方案数就是 .
但是现在有 ,考虑将其容斥为 .
具体地,枚举一个集合 表示钦定这个集合内的 强制钦定为不满足剩余的无限制,其容斥系数为 ,将钦定不满足的 变为 ,和其他的 放在一起排序,求个 ,最后无限制的就是一个排列数。
根据这个容斥列 dp,设 为考虑完了前 个 ,钦定了 个 是不合法的,其带容斥系数的方案数是多少。 的正常转移, 转移的时候多带一个 的容斥系数。最后统计答案的时候将 求和即为答案。Code .
「HEOI2013」SAO
回忆一个外向树的拓扑序计数是如何解决的。对于所有的 种方案,必须要满足根在所有子孙的拓扑序之前,那么方案书就是 ,然后就可以剥去根不考虑根的印象。之后每次再考虑剩余若干子树的一个根 ,要满足 出现在它所有子孙之前,那么方案数就会除掉 ,之后 就对总方案数没有了影响,可以剥除。所以外向树的拓扑序个数是 .
现在有了内向边,同时有内向边和外向边不是很好做,我们现在只会做只有外向边。
考虑容斥,选出 条内向边,钦定它们是一定不满足的,剩余的内向边满足与否都无所谓。那么这种情况的方案数就是把选出的内向边看成外向边,其余的当作不存在(也就是这条边的限制满足与否都无所谓),然后对连通块分别求出拓扑序,再利用组合数乘起来(此时连通块之间不存在影响了),容斥系数就是 .
基于这个容斥,列出 dp,令 表示考虑 以内的子树,一共钦定了 条内向边是不满足的。但是发现由于需要对拓扑序计数,还要记一个当前 所在连通块的总和为 ,这样状态数就达到了 ,不能接受。
考虑我们最终只是想要求 ,那么就可以令 ,换而言之,令 为考虑 子树内,所有钦定方案的,带容斥系数的拓扑序数之和。转移即为一个树形背包,在钦定一条内向边一定不满足的时候,乘上一个 的容斥系数来转移即可。
时间复杂度 .Code.
2022 ICPC Shenyang E
https://codeforc.es/gym/104160/problem/E
不是很难,先鸽着
upd on 2023.4.21:模拟赛考到这题,然而没记起来在这里见过,这就是鸽子的报应/cy
树怎么做?容斥,枚举一个边集钦定其是割边,然后剩下的随便连,每个没有被钦定的边连成的连通块方案数都是一个和 size 有关的 2 的次幂。那就树形背包 表示 子树内 所在连通块大小是 ,带容斥系数的方案数是多少,转移的时候就分钦定割边和不钦定两种情况。
图怎么做?边双缩点之后做一个类似的 dp 就行。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?