容斥原理再探

容斥原理再探

前传

全集 U 种有若干元素,每个元素 xi 都有若干个不同的属性 pj.令 Ai 为满足第 i 个属性的集合。现有 n=|U| 个元素,m 个属性,欲求 |jmAj|,记 A^j=UAj 即不满足第 j 个属性的元素构成的集合。

艾弗森记号是有力的工具。

|jmAj|=injm[xiAj]=injm(1[xiAj])=inT{1,2,,m}((1)|T|jT[xiAj])=T{1,2,,m}(1)|T||jTA^j|

这就得到了计数问题中容斥原理的常见形式,考虑其组合意义:

计数问题中,全集即为所有方案构成的集合。

|jmAj| 意思是,这 m 种限制全部满足的方案数是多少。

|jTAj^| 的意思是,枚举了一个集合 T,强行钦定这些限制是不满足的,其余的任意,一共有多少方案。将其乘上其容斥系数 (1)|T| 再求和即为所求方案数。

另一方向的也类似:

|jmAj|=|U||jmA^j|=|U|injm[xiAj]=|U|injm(1[xiAj])=|U|inT{1,2,,m}((1)|T|jT[xiAj])=T{1,2,,m},T(1)|T|+1|jTAj|

注意:jTAjT= 的时候应为 |U|

而在一类通过容斥和 dp 解决的问题中,会选择直接带着容斥系数 dp 方案数。且看例题:

「CSP-S 2019」Emiya 家今天的饭

就这也叫容斥?

第三个限制很愤怒,先不管它,算出所有的方案,再容斥掉不合法的,然后就会发现,只需要一层容斥就可以了。

具体地,枚举哪个主要食材是超了的,在这上面做个 dp,以 fi,j,k 表示考虑了前 i 个烹饪方法,一共烹饪了 j 个菜,而且已经用食材 x 烹饪了 k 个菜,方案数是多少。为了能够转移 f,还需要预处理出每一行的 a 之和。这样时间复杂度是 O(n3m)

但是注意到最终统计答案的时候只关心 k 是否大于等于 (jk),所以令 fi,j 为考虑前 i 个烹饪方法,用食材 x 烹饪的菜的个数,减去不用食材 x 的菜的个数为 j,方案数是多少。这样复杂度就降到了 O(n2m)Code

ARC096E Everything on It

考虑将第二个容斥掉,枚举有 1i 出现次数 1 次,剩余的无限制,假设其方案为 f(i)

那么答案就是 f(i)(1)i(ni)

考虑 f(x) 怎么算,令 y=nx,首先考虑不包含 1x 的子集一共有 22y 个,然后再考虑包含 1x 的子集,相当于将 1x 分成若干个不同的集合,每个集合从 2y 个集合中找一个集合,与其的并集构成一个新的集合。

si,j 为将 1i 分成若 j 个不同的集合的方案数(第二类斯特林数),枚举有 1x 中出现了的有 i 个,一共分成 j 个集合,那么就有:

f(x)=ijsi,j(2y)j22y(xi)=22yj(2y)ji(xi)si,j

考虑后面那个求和号的组合意义,就是从 x 个元素中选出 i 个元素,再将这 i 个元素划分成 j 个集合。如果把没有选出的元素也看成一个集合,那么其就是 x 个元素划分成 (j+1) 个集合,其中有一个集合有标号且可空。所以:

f(x)=22yj(2y)j((j+1)sx,j+1+sx,j)

要注意 22y 计算时要将指数模 M1

Code

「ZJOI2016」小星星

现在有大小均为 n 的图 A=(V,EA) 和树 B=(V,EB),求符合条件的排列 p 的个数,满足若 (i,j)EB,则 (pi,pj)EA

比较容易理解的容斥,但并不是很容易想到要用容斥,要将什么条件容斥掉。

考虑一个暴力 dp,fi,j,S 考虑了 B 中考虑 i 的子树,点 i 映射到了图中的点 j,已经被映射到的点集是 S

暴力 dp 是 O(n33n),考虑到它的第三维是个子集卷积,难以优化,需要想办法规避掉子集卷积。

回想一下为什么要记录 S,在 dp 过程中可以枚举当前点映射到了哪个点,这样已经满足 B 中每个点映射到了 A 中的一个点,为了要满足映射到的点两两不同,即 A 中的点都被映射到,所以需要记录 S

那么就将这个容斥掉,枚举 A 中一个集合 S,钦定这个 S 中的点没有被映射到,方案数乘上容斥系数 (1)|S| 求和即为答案。

枚举 S 后,没有了“映射到的点两两不同”这个限制,于是乎可以直接 fi,j 为考虑子树 i,且点 i 映射到了 j 的方案数,容易做到总时间复杂度 O(n3) dp.总的复杂度就是 O(2nn3)

虽然最终答案不会爆 long long,但是中间的 dp 可能会爆 long long,可以用 unsigned long long 直接自然溢出啥事没有,用 long long 的溢出似乎也能过,但是其实是 UB.Code

「2021 山东三轮集训 Day2」体育测试

给定序列 a,求合法排列 p 的方案数使得:

  • ai>0,则满足 ip 中出现位置 ai
  • ai<0,则满足 ip 中出现位置 |ai|

n5000,模 109+7

首先考虑如果只有 ,将 a 从小到大排序,那么方案数就是 (aii+1)

但是现在有 [|ai|],考虑将其容斥为 (1[|ai|1])

具体地,枚举一个集合 S 表示钦定这个集合内的 强制钦定为不满足剩余的无限制,其容斥系数为 (1)|S|,将钦定不满足的 |ai| 变为 |ai|1,和其他的 放在一起排序,求个 ,最后无限制的就是一个排列数。

根据这个容斥列 dp,设 fi,j 为考虑完了前 ia,钦定了 j 是不合法的,其带容斥系数的方案数是多少。 的正常转移, 转移的时候多带一个 1 的容斥系数。最后统计答案的时候将 fn,i(ni)! 求和即为答案。Code

「HEOI2013」SAO

回忆一个外向树的拓扑序计数是如何解决的。对于所有的 n! 种方案,必须要满足根在所有子孙的拓扑序之前,那么方案书就是 n!n!(n1)!=n!n,然后就可以剥去根不考虑根的印象。之后每次再考虑剩余若干子树的一个根 x,要满足 x 出现在它所有子孙之前,那么方案数就会除掉 sizx,之后 x 就对总方案数没有了影响,可以剥除。所以外向树的拓扑序个数是 n!sizx

现在有了内向边,同时有内向边和外向边不是很好做,我们现在只会做只有外向边。

考虑容斥,选出 i 条内向边,钦定它们是一定不满足的,剩余的内向边满足与否都无所谓。那么这种情况的方案数就是把选出的内向边看成外向边,其余的当作不存在(也就是这条边的限制满足与否都无所谓),然后对连通块分别求出拓扑序,再利用组合数乘起来(此时连通块之间不存在影响了),容斥系数就是 (1)i

基于这个容斥,列出 dp,令 gi,j 表示考虑 i 以内的子树,一共钦定了 j 条内向边是不满足的。但是发现由于需要对拓扑序计数,还要记一个当前 i 所在连通块的总和为 k,这样状态数就达到了 O(n3),不能接受。

考虑我们最终只是想要求 gi,j,k(1)j,那么就可以令 fi,k=gi,j,k(1)j,换而言之,令 fi,k 为考虑 i 子树内,所有钦定方案的,带容斥系数的拓扑序数之和。转移即为一个树形背包,在钦定一条内向边一定不满足的时候,乘上一个 1 的容斥系数来转移即可。

时间复杂度 O(Tn2)Code

2022 ICPC Shenyang E

https://codeforc.es/gym/104160/problem/E

不是很难,先鸽着

upd on 2023.4.21:模拟赛考到这题,然而没记起来在这里见过,这就是鸽子的报应/cy

树怎么做?容斥,枚举一个边集钦定其是割边,然后剩下的随便连,每个没有被钦定的边连成的连通块方案数都是一个和 size 有关的 2 的次幂。那就树形背包 fx,i 表示 x 子树内 x 所在连通块大小是 i,带容斥系数的方案数是多少,转移的时候就分钦定割边和不钦定两种情况。

图怎么做?边双缩点之后做一个类似的 dp 就行。

posted @   do_while_true  阅读(373)  评论(5编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?

This blog has running: 1837 days 12 hours 56 minutes 35 seconds

点击右上角即可分享
微信分享提示