计数(3):容斥与反演
我们会……会用一辈子容斥吗。
子集反演我爱你!
波奇酱太可爱了呜呜呜好可爱好可爱好可爱
看完了孤独摇滚,完结撒花!
鸣谢 Mirasycle 大蛇的容斥博客。因为我完全就是抄他的框架的不要什么都说出来啊
基本形式
拥有若干个集合 \(S_1, S_2, \dots, S_n\),那么就有
部分反演
你发现基本形式似乎没卵用,我们还是需要用伟大的子集反演对应用进一步细化。接下来这部分我们将要从零开始反演 qwq。
基本概念与性质
令 \(F(n) = \sum\limits_{i = 0}A[n, i]G(i)\),\(G(m) = \sum\limits_{i = 0}B[m, i]F(i)\),那么认为 \(F,G\) 构成了一对反演关系。
因此我们将 \(F, G\) 看作一个列向量,\(A, B\) 看成两个矩阵,就有
\(F = A\times G, G = B\times F\)
我们带入一下就会发现
\(F = A\times B \times F\)
因此 \(A, B\) 互为逆矩阵。这是非常伟大的一件事,我们考虑用矩阵的方法分析反演的一些性质。
-
矩阵转置后仍然互逆。
把乘法定义式写出来 \((A\times B)_{i, j} = \sum\limits_{k = 0}A_{i, k}B_{k, j}\) 写出来显然就出现了。这个让我们可以得以同时交换 \(F, G\) 中的指标,得到新的反演关系。
-
\(A, B\) 同时数乘 \(\pm 1\) 仍然互逆。
这个性质给下面的性质做好了铺垫。
-
我们可以随意的将 \((-1)\) 的整数次幂在系数中移动。
看 cmd 的文章的时候对此不是很理解,这里我感觉我们直接从代数形式的角度来看更方便。
\[F(n) = \sum\limits_{i = 0}A[n, i]\sum\limits_{m = 0}B[i, m]F(m) \\ = (\sum\limits_{m = 0}\sum\limits_{i = 0}A[n, i]B[i, m])F(m) \\ = [n = m]F(m) \]这启发我们:对于 \(A[n, i]\),\(B[i, m]\) 如果带有一个 \((-1)^i\) 或者 \((-1)^n\),\((-1)^m\) 作为系数,我们可以先把它们给合并起来,然后通过乘上 \((-1)^{n - m}\),\((-1)^{m - n}\) 等手段(这样的“手段”充要条件是此函数 \(P(n, m)\) 在 \(n = m\) 时一定要等于 \(1\)),吃掉一个不好看的指数,最后重新分配。通过此手段达到移动 \((-1)\) 的目的。
接下来给出简明的操作
- 将 \(G\) 改写成 \(G(i) = \sum\limits_{m = 0}B[i, m]F(m)\)。(这样在后面分配系数的时候会清晰一点)
- 合并 \(A[n, i], B[i, m]\) 上的 \((-1)\) 次幂 \((-1)^t\)。
- 给 \((-1)^t\) 乘上 \(P(n, m)\),其中 \(P(n, m)\) 满足 \(n = m\) 时取值为 1.
- 将 \((-1)^tP(n, m)\) 重新分配给 \(A[n, i], B[i, m]\)。
我们将在下面看到此小技术的应用。
二项式反演
四种形式
无疑,这是一个优美的式子,它的代数证明很简单,直接展开即可。
依据上面的技术,我们这样来做
\(G(i) = \sum\limits_{m = 0} (-1)^m {i\choose m} F(m)\)
合并系数:\((-1)^{i + m}\)。
乘上 \((-1)^{n - m}\),然后做一个小调整,将系数变为 \((-1)^{n - i}\)。
全部分给 \(F\) 的系数。
(当然其实也可以把后面的 \((-1)^i\) 分给 \(G\),然后就得到 \(F(n) = \sum\limits_{i = 0}(-1)^n{n\choose i}G(i) \iff G(n) = \sum\limits_{i = 0}(-1)^n{n\choose i}F(i)\)。
不过把 \(G(n)\) 内的系数 \((-1)\) 给吸纳进 \(F\) 里面去似乎就可以得到下面一样的结果了……哦原来 cmd 老师说的 \(F, G\) 内的移动是这样的嘛……
这个式子实际上也是很多容斥的式子。非常的好用。
我们将两个矩阵转置可以得到分别的两个形式。以第一个为例。首先我们把系数的 \(n, i\) 翻转\(F(n) = \sum\limits_{i = 0}(-1)^n{i\choose n}G(i)\iff G(n) = \sum\limits_{i = 0}(-1)^n{i\choose n}F(i)\)。接下来按照上面所说的小技术把 \((-1)^{n +i}\) 换为 \((-1)^{i + m}\),将它们分配成 \((-1)^i\) 与 \((-1)^m\) 后可得。
接下来还是一样的操作方法:我们把 \(G(i)\) 里面的 \((-1)^m\) 给合并上去得到 \((-1)^{i + m}\),变换为 \((-1)^{i - n}\) 全部分给 \(F\) 的系数。
利用 egf 的证明
这个证明用于证明形式二,非常漂亮。
\(G(n) = \sum\limits_{i = 0}{n\choose i} F(i)\)。我们记 \(G, F\) 分别它们的 egf 那么有 \(G = Fe^x\)。则 \(F = Ge^{-x}\)。展开就行了。
二项式反演组合意义
恰好,至多,至少
聪明的小朋友一定都已经看出来了,二项式反演看上去和容斥像是有千丝万缕的联系。不过不妨抛开容斥。
对于第一个形式,我们尝试用组合意义翻译一下:令 \(F(n)\) 为至多有 \(n\) 个元素被钦定了的方案数,枚举的 \(i\) 是确实被钦定的数量。\(G(n)\) 为恰好有 \(i\) 个元素被钦定了方案数。元素之间无标号,即相互等价。
对于第二个形式,\(F(n)\) 为至少有 \(n\) 个元素被钦定了的方案数。枚举的 \(i\) 是确实被钦定的数量。
子集反演及其组合意义
证明无非就是把右边打开然后啦,没什么好讲的。
我们来观察一下它和二项式反演之间的关系,还是很容易看出来的:二项式反演要求 \(n\) 个元素相互等价,但是子集反演不需要。用人话描述一下子集反演两个式子就是:第一个式子为,至多是 \(S\) 内的元素被钦定,第二个式子是至少 \(S\) 内的元素被钦定,其它任意。二项式反演和子集反演的区别在于二项式反演要求元素之间相互等价,无标号,子集反演则对此无要求。总之关键在于钦定。
关于容斥系数的一个推论
如果 \(F(S) = \sum\limits_{S\subset T}G(T)\),最后要求出 \(\sum\limits_{\empty \not= S\subset U}G(S)\),那么:
翻译一下:对于全体 \(G\) 除去空集求和,那么容斥系数是 \((-1)^{|T| + 1}\)。
多维的子集反演。
其实没啥区别,就是把一元函数改成二元函数而已。
基础题
以下是最基础的二项式反演和子集反演应用。核心思想是:恰好难做->钦定一部分->反演。
P6442
时隔很久仍然无法一眼秒,我都做过这题,如果我当时不知道这是容斥我应该不太能够独立做出来/yun
发现并集为全集是一个相当强大的约束无法战胜,于是我们考虑正难则反:如果我们再减去没有到全集的情况呢?但是这也仍然很困难。如果我知道这是容斥的话,那么现在你就闻到这个味道了,统计 \(f(S)\) 为集合并为 \(S\) 子集的方案数,最终答案是 \(\sum\limits_{S}(-1)^{n - |S|}f(S)\)。随便 sos-dp 即可。
现在我已经整理了高贵的二项式反演和高贵的容斥原理的式子,再次大战!直接 dp 离不开“并集为 \(S\)”,这很难了。考虑钦定 \(S\) 内的元素一定会被用上,其它的任意,计算 \(F(S)\) 是一个 sos-dp,对着这个东西子集反演
子集反演你就是我的神。与其说这是钦定,不如说是一个放宽条件。
P3349
csy 上课教过,设计 dp 可以从两个角度,一种从判定(我个人认为人话来说就是,用尽量少的,常数个变量(或者值域小)的设计最终状态的判定,然后把这常数个变量扔进 dp 状态就可以进行合法状态的整合了),以及状态的分割(比如区间 dp 分开化成两个子区间,比如树形 dp 上用子树合并,我个人认为本质上可以看成将判定过程看作一个递归判定,做一个归纳。所以这中间的变量仍然要记录在状态内,如树上背包)实际上即便是第一种情况也必须要在一个“增量”的情况下进行。好吧我开始混乱了等下去看他的讲课/kel
咳咳扯远了。我们回到这道题。简化题面是:给定一张图,求问有多少个置换使得将此图上的点编号置换后为给出的生成树。直接枚举全排列判定固然是 \(O(m)\) 的但是这时候答案的构造并不满足“可以增量”所以一般是不会考虑的。增量的考虑就是考虑子树再合并到父亲上面去,考虑父亲和儿子合并的时候的判定,此时我们发现只和儿子的置换方案 \(p\) 和当前父亲的置换方案 \(q\) 有关,要求 \((q, p)\) 边是存在的。为了保证 \(p, q\) 不重复我们需要再加一个维度 \(S\),\(f[u, x, S]\) 为对于点 \(u\) 当前置换为 \(x\),目前已经用了 \(S\) 内的点了的方案数。
中间要一个枚举子集(实际上并不完全,因为只要枚举 \(siz[v]\) 大小的子集即可,复杂杜不太会算,注意到题解里面说这能过,牛大了),不是很能跑的过去。注意到 \(S\) 非常的鸡肋,我们考虑砍掉这个 \(S\) 状态。那么怎么样保证不重复呢?正难则反的,考虑减掉一定重复的情况!一定重复其实并不容易,但是我们仍然可以把“必须重复”这个“等于号”换成“重复的点集合在 \(S\) 内”这个“小于等于号”此时就可以愉快的容斥了。时间复杂度 \(O(n^32^n)\),能过真无敌了(.
听说还有子集反演的做法,好牛。
是的我现在明白什么子集反演了。进度回溯到“考虑砍掉 \(S\) 这个状态”,必须满足 \(S\) 这个约束我们不妨转化成钦定使用的点必须在 \(S\) 内,这样求出来 \(f(S)\) 代表颜色在 \(S\) 内。那么子集反演一下
观察两题中我们写的心路历程,都是正难则反->反着是一个“等于号”,也很难->换成更为宽松的“小于等于号”->容斥。如果是从子集反演的角度的话,只需要暴力 dp->每次怎么都是“恰好为 \(S\)”->如果变成 \(S\) 的子集会不会好做很多,换句话说如果我钦定要满足 \(T\) 内的条件其它任意会不会好做很多->子集反演。
P5505
首先考虑没有所有人必须拿到的约束,这个很好做随便组合数一下就行了,也就是至多有 \(n\) 个人的答案 \(F(n)\)。令恰好有 \(x\) 个人拿到了那么就有 \(F(n) = \sum\limits_{x = 0}^{n}{n\choose x}G(x) \iff G(x) = \sum\limits_{n = x}{n \choose x} (-1)^{n - x}F(x)\)
P2167
\(S\) 为字符串集,能匹配上 \(S\) 内的字符串数量很容易计算。然后子集反演。这题是能解决的问题似乎没办法做到“恰好诶”->退一步“钦定”太容易啦->子集容斥秒了。
P4859
这个恰好都写在脸上了,只需要钦定 \(x\) 组即可。简单分析即可 dp 了。
P3270
反射容斥
dashena
可恶啊这和上面说的容斥真的有关系吗?好吧这既叫做容斥那么也放到熔池里面来八。
波奇酱好可爱!店长好可爱!
引子
你在 \((0, 0)\),要求走到 \((n, m)\),每次可以向右,向上走一步,但是不能触碰到 \(y = x + b\) 这条直线。问方案数。
sol:真的神。
首先不考虑约束是 \({n + m}\choose n\) 种方案数。考虑约束,将第一次相交前的路径按照 \(y = x + b\) 这条直线对称过去,那么就变成了从 \((-b, b)\) 开始往上往右走然后再走到 \((n, m)\) 的方案数。等价于 \((0,0 )\) 走到 \((n + b, m - b)\)。
简单的证明一下这两者成双射关系,对于任意一个 \((-b, b)\) 走到 \((n, m)\) 显然要经过 \(y = x + b\) 这条直线(因为 \(y = x + b\) 将平面分成两个半平面,\((-b, b)\) 在这头,\((n, m)\) 在那头),对称过去就变成从 \((0, 0)\) 开始过 \(y = x + b\) 了,这是唯一的。而对于任意从 \((0, 0)\) 开始过 \(y = x + b\) 也是能够唯一对应一个的。这样就形成了双射关系。
答案是 \({{n + m}\choose n} - {{n + m}\choose {n + b}}\)
流程
我们增加一条直线,不能碰到 \(A:y = x + b, B:y = x + c\)。我们认为 \(b > 0 > c\)。
沿用上面正难则反的思路(或者说是一步的容斥):总方案数等于:随便走-最后一次过 \(A\) 的-最后一次过 \(B\) 的。
为了方便描述,对于路径,过 \(A\) 和 \(B\) 的时候我们都记录下来。特别的,我们不会记录连续的 \(A\) 与 \(B\)。最后形成的串为 \(S\),\(f(S)\) 为 \(S\) 为触碰串前缀的方案数。举个例子,比如 \(S = AB\),那么 \(f(S)\) 就是 \(AB, ABA, ABAB, ABABA\dots\) 的方案数。
\(f(S)\) 是比较容易计算的。依次处理,每次将另一条直线和路径前半段给按照此直线翻折过去。最后我们计算一下原点的坐标即可。
答案如何计算?考虑最后一次过 \(A\) 的方案数。总集 \(f(A)\),我们要减去最后一次过 \(B\) 的方案数 \(f(AB)\) 又要补上 \(f(ABA)\)……对于 \(B\) 同理,那么答案就是 \(f(\empty) - f(A) - f(B) + f(AB) + f(BA) - f(ABA) - f(BAB) +\dots\)。
这样是不是要反复做无限次呢?每次 \((0,0)\) 总会在一个维度上拓展 \(1\),所以最后只会做 \(O(n + m)\) 次。
接下来我们令 \(c>0\)。
我们来导一下。如果一开始过 \(A\),后面经过了 \(x\) 次 \(A\),\(y\) 次 \(B\),那么原点坐标 \((0, 0)\to (-xb - yc, xb+yc)\),也就是 \((n + xb + yc, m - xb - yc)\), 一开始过 \(B\) 那么 \((0, 0)\to (xb + yc, -xb - yc)\),也就是 \((n - xb - yc, m + xb + yc)\)。当 \(x = y\) 时容斥系数为 \(1\),\(|x - y| = 1\) 时容斥系数为 \(-1\)。我们可以将先过 \(B\) 看作是 \(A\) 中经过了 \((-x)\) 次 \(A\),\((-y)\) 次 \(B\)。那么就有:
P3266
初遇此题,省选前夕和 yzy 一起看的。短短几个月过去沧海桑田,yzy 投入了文明六的怀抱,我也彻底认清了我毫无前途是个废物的事实,令人感慨。
不扯了。首先最基本的暴力是要会的。
for(int i = 1; i <= n + 1; i++) {
for(int j = m + 1; j >= 0; j--) {
upd(f[i][j], f[i][j + 1]);
if(j > 0)
upd(f[i][j], f[i - 1][j - 1]);
}
}
处理边界条件需要注意,要让转移规律!
我们用几何的方法把图画一下
上面的 dp 是从红点走到左上,我们给坐标系线性变换一发就变成了下面这样,每次可以向右或向上一步,不能经过绿线,求到右上角的方案数。这就是反射容斥的形式了。套板子。
uoj424
实际上是对笛卡尔树形态计数,考虑什么时候这个笛卡尔树是可以填上树使得成为一个“挺好序列”。左子树都严格小于根,右子树都小于等于根。此时很显然这样是最优的:对于根权值 \(v = m\),左儿子为 \((v-1)\),右儿子为 \(v\),如果从根到某个叶子经过的左儿子边大于 \((m - 1)\),那么就不合法。这显然是判定的充要条件。
设 \(f[i, j]\) 为 \(i\) 个点的笛卡尔树,最长左链长度小于等于 \(j\) 的情况,\(f[i, j] = \sum\limits_{x = 0}^{i - 1} f[x, j-1]f[i - 1 - x, j]\)。
这么爱卷积?卷起来!设 \(F_j(x)\) 作为这一列 \(f(i, j)\) 的 ogf,有
然后我就不会做了,这东西没办法反射容斥。
注意这个卷积形式长得和 Catalan 数特别像,所以我们可以联系到括号匹配(啊?)。对于一个一般的二叉树,递归的我们给左儿子外面套上一对括号,右儿子括号序列照抄。到了这题里面,令左括号为 \(+1\),右括号为 \(-1\),那么前缀和不能超过 \(m\)。变换坐标系即可反射容斥。
奇怪的小 trick + 1:对于形如 \(f[i]f[n - 1 - i]\) 考虑括号匹配的方式描述(这都什么东西啊哼哼哼啊啊啊)
基础题
图连通块计数(tip:单步容斥)
P100982
注意到联通图很难技术,但是不联通天然给了我们一个子问题划分的方式。并且没有这条约束时非常容易的 \(2^{n\choose 2}\)。于是我们考虑正难则反。考虑 \(1\) 所在联通块的计数,令 \(1\) 所在联通块大小为 \(x\),\(1\) 联通块的数量就是 \(f_x{n - 1\choose {x-1}}\)。向外一条边不能连,然后还要带上 \(2^{{n - x}\choose 2}\) 这个系数。
ARC105F
怎么处理“二分图”这个约束?-> \(n\) 超级小->增量加点再考虑连边,设 \(f[i, S]\) 为前 \(1\sim i\) 个点左部点为 \(S\) 集合内的点。很容易转移。然后回出现这样的问题,如果没有连通图的约束这个也是错的,因为对于同一种方案,如果有 \(c\) 个联通分量那么会计数 \(2^c\) 次,其次计数的时候根本没考虑连不连通这档事,就很坏。不过换个角度考虑毕竟只有一个联通块那么就算是 \(2^n\) 分配点集也很容易计算。而且这个 \(n\) 很小一脸子集反演的样子(真的吗?)
以上是一些胡思乱想。我们认真考虑这档子事情。我必须承认我完完全全想错了,我以为 \(f[i, S]\) 直接计数会产生 \(2^c\) 的系数是无法接受的,但是实际上是你只要减掉不连通的情况即可。类似上面的做法,\(f[S]\) 为以 \(S\) 内的点组成的没有区分黑白点的二分图数量,\(g[S]\) 为联通二分图数量。考虑所有 \(lowbit(S)\) 所在的子集 \(T\),则要减去 \(g[T]f[S - T]\)。转移 \(f, g\) 均是 \(O(3^n)\)。
这tm怎么都没用到容斥啊。
注意一下 \(f\) 递推的方法,考虑 \(lowbit\) 的贡献。\(lowbit\) 作为选中点那么会向外面产生 \(2^{\operatorname{popcount}(S) - 1}\) 次点贡献,如果是被选中点那么也会产生 \(2^{\operatorname{popcount}(S) - 1}\)
总结
如果一个问题强制加入了“图联通”,并且容易做图不连通的情况,那么就正难则反,不连通数量等于考虑其中某个点钦定在某个联通块内乘上连通块外任意的方案数。
P6789
题号好评。
首先我们考虑如何计算一张图的最大基环树森林。对于一个联通块,Kruskal 第一次出现在同一个集合的边也加进去。现在考虑优化。考虑一条边在多少个场合下会被加进来(当然可能并没有这么严苛)。首先边从大到小排序,对于边 \((u, v)\) 能被加进来的充要条件是
- \(u, v\) 在同一个联通块,但是这个联通块是树。
- \(u, v\) 不在同一个联通块。
令人愉快的事情在于我们并不在乎边权只在乎形态了。
对这两种情况分别计数。注意到这还是很难,因为你很难将联通块的划分放到状态里面去。考虑钦定一个联通块,别的边任选,然后利用容斥等手法去重。考虑钦定 \(u\) 所在的联通块集合为 \(S\)。\(f[i,S]\) 为前 \(i\) 条边 \(S\) 内的点集构成一个联通块树的方案数,\(g[i, S]\) 为前 \(i\) 条边 \(S\) 内的点集任意的方案数,\(h[i, S]\) 为 \(S\) 内的点构成联通图方案数。现在计算贡献,钦定 \(u\in S\)。考虑构造好 \(u\) 所在的联通块。
如果 \(v\in S\),那么贡献就是 \(f[S]\times g[i, U - S]\)。很容易理解。如果 \(v\not \in S\) 否则就是 \(g[i, U - S - T](f[i, S]\times h[i, T] + f[i, T]\times h[i, S] - f[i, T]f[i, S])\)。请注意我们这里面计数的重心在于 \(u\) 所在的联通块。
现在我们考虑 \(f, h, g\) 的转移。
\(g\) 没必要考虑,\(h\) 就是简单的图联通计数。
对于 \(f[i, S]\) 需要考虑最后一次连边。每个形态都会被计算 \(\operatorname{popcount(S)} - 1\) 次,要除以掉它。
DAG 相关
P6846
什么牛题。
遇事不决考虑判定。一张有向图有环:topo 排序后无法全部便利一遍,或者说构造出一颗 dfs 外向森林,如果存在返祖边说明有环。这是两种可能的想法。对于外向森林,首先你要满足 dfs 这档子事情,很有难度,所以不考虑。尝试从 topo 的角度入手,如果不行再考虑别的。
我们发现一件事情:如果你用 \(x\) 次操作改变了一些边变成了 DAG,相应的你可以用 \((m - x)\) 次操作反向一下。因此求改变边数是在骗哥们,本质让你求这张无向图多少种定向方法变成 DAG 的方案数为 \(c\)。答案是 \(\dfrac{c}{2}m\)。
考虑 topo,每次删除入度为 \(0\) 的点这样来做计数。令当前入度为 \(0\) 的点集为 \(S\),\(S\) 要满足的条件一定是 \(S\) 为独立集合。是不是意味着 \(f[S]\) 为 \(S\) 内的点构成 DAG 的定向数,那么 \(f[S] = \sum\limits_{T\subset S, T \operatorname{是独立集}}f[S - T]\) 吗?实则不然,因为你可能这一次无法去除所有入度为 \(0\) 的点,只是它的一个子集——很好,这很子集反演。
把式子推导一下,\(h(W)\) 代表集合 \(W\) 是否为独立集。
于是我们得到了答案的式子。
多推两遍把。
ABC306Ex
不幸的是如果没有等号就变成了上面那题了。幸运的是有了等号我们可以把一个点集合看成一个单点。这样的话 \(h(W)\) 要做一些处理,计算 \(h(W)\) 内的联通块数量,联通块内部只能选择 \(=\) 号,\(|T|\) 看作是联通块数量。没了。
这让我感觉有点怪。没完全理解。
P11714
首先考虑判定一张强连通图,要缩点。缩点后一个点那么就是一张强连通图,是一个 DAG 就是一个非强连通图。单点条件很严苛,正难则反。如果我们已经知道每个点属于哪个强连通分量,那么做一次 DAG 子图计数就能计算出来不合法的方案数。问题在于我们不知道每个点属于哪个强连通分量。但是实际上我们并不在乎整个 DAG 的具体形态,而是只在乎“它是一个 DAG 而不是一个单点”。为了描述这件事情我们只需要找到一组入度为 \(0\) 的强连通分量即可,剩下的不用在乎。
先设 \(E_{S, T}\) 为 \(S\) 到 \(T\) 边数,\(H_S\) 为 \(S\) 内部边数。
\(f_S\) 为 \(S\) 内所有点在一个强连通分量的方案数,总方案数 \(2^{H_{S}}\)。要减去不合法的方案数。根据上面的我们枚举 \(T\subset S\),代表钦定 \(T\) 内的点缩点后形成的强连通分量是 DAG 中入度为 \(0\) 的点,其它任意。因为这每次只会考虑到一个子集,通过子集反演可以得到形成 \(t\) 个联通分量那么容斥系数为 \((-1)^{t+1}\)。我们无法在计算 \(f_S\) 时通过枚举 \(T\) 的方式直接得到容斥系数。需要在计算 \(T\) 内部连边方法时计算。\(T\) 之外 \(T\) 到 \((S - T)\) 的连边任意,\((S - T)\) 内部连边也任意,这部分是 \(2^{E_{T, S - T} + H_{S - T}}\) 的。
令 \(g_T\) 为形成奇数个强连通分量的方案数减去形成偶数个强连通分量。那么 \(f_S = 2^{H_{S}} - \sum\limits_{T \subset S, T\not = \empty} g_T2^{E_{T, S - T} + H_{S - T}}\)。现在对 \(g\) 计算。如果没有容斥系数那么 \(g_S = \sum\limits_{\operatorname{lowbit(S)}\in T\subset S}f_Tg_{S - T}\)。现在有了容斥系数,奇偶数量变化,这些都要取反,特别的 \(T = S\) 时 \(f_T\) 不用取反。\(g_S = f_S - \sum\limits_{\operatorname{lowbit}(T)\in T \subsetneq S} f_Tg_{S - T}\)。我们发现很严重的事情在于是不是计算 \(f_S\) 的时候要用到 \(g_S\)。但是 \(g_S\) 中 \(f_S\) 这部分代表的是 \(S\) 全在一个连通分量中的方案数,在 \(f\) 中是合法的,不应该减去。因此我们先处理 \(g_S\),令此时 \(f_S\) 为 \(0\),然后再处理 \(f_S\),最后把 \(g_S\) 加上 \(f_S\) 即可。
本来对于 \(E\) 我是用 \(O(3^n)\) 写的,但是因为我调用了 \(O(3^n)\) 次 unordered_map 常数爆炸导致跑的还没还有 \(O(n3^n)\) 快(悲。
点减边容斥
事情是这样的,20250813 我在模拟赛中斩获 rnk 78,成为全场垫底。在 20250814 中,我再模拟赛连续两天斩获 rnk78,又一次成为了全场垫底,被点减边容斥肘飞了。这就很悲惨。我下定决心我一定不能被点减边容斥创飞了。
ABC390F
从小唐题入手。
值域上虽然是条链也可以看成一棵树。
考虑一下加入一个点对一个集合的贡献。利用一点点减边容斥的思想,将 \(x\) 加入集合 \(S\) 内且 \(x\not\in S\),点数量始终会 \(+1\),边数量要看 \((x - 1), (x + 1)\) 是否存在。分别计数。
此时我们就可以发现点减边容斥的好处:容易独立出来点和边的贡献,分别计算,而让我们可以忽略这个联通块的形态。
XYD19495.热异常/牛客 Haitang and diameter
牛的。
如何不重不漏计数直径?找一个特殊点来计数。特殊的点就在于直径的中点,因为对于一棵树,直径的中点必然重合。比较困难的事情有两件,首先是你有的中点在边上,这个东西不方便我们刻画,这是长度为奇数的情况。其次是因为 \(0\) 边存在所以中点实际上可能是一个联通块,不过这是长度为偶数的情况。
更加详细的我们来对这两件事情研究研究,对于第一种情况上,边的边权为 \(1\),扔掉这条边到两边的距离都是相等的。对于第二种情况上,为了不枚举联通块我们考虑点减边容斥拆分点和边的贡献。对于每个点的贡献系数为 \(1\),每个边的贡献系数为 \(-1\)。对于点的话,只需要考虑这个点恰好是中点即可。对于边,注意到这个边边权为 \(0\)(第二种)和边权为 \(1\)(第一种)作为中点的话,去掉这条边两边的情况是一样的,系数相反,所以抵消了,不算贡献。于是问题转化成对于每个点 \(u\) 考虑它作为直径严格中点的直径条数。
考虑 dp,这个 dp 其实挺有手法的。对于一个树上直径的 dp,通常的手法是在外面界定一个最大值,要求最长的不超过这个最大值。通过一些手法变成等于也是不难的。对于 \(u\) 统计以 \(u\) 为根后半径长 \(x\) 的可能直径数量。这个计数中包含不同直径和不同赋值两部分。不同直径,如果是合并两个子树最深就是半径,那么要统计最长半径恰好为 \(x\) 的点数目,两两相乘。如果是合并两个子树最深小于等于半径,那么要统计不同的赋值情况。所以不难设计出状态 \(f[u, x], g[u, x]\) 分别代表最深为 \(x\) 的赋值情况和点数目。对于 \(f[u, x], g[u, x]\) 直接合并子树统计的时候顺带更新最大就行了。对于最后统计答案的时候两部分分开讨论,对于子树 \(v\) 最大深度为 \(x\) 实际最大深度 \((x+w)\),如果 \((x+w) \le y\) 那么 \(f[v, x]\) 会被乘进对于 \(y\) 为半径的贡献里面。如果 \((x+w)=y\) 那么 \(g[v, x]\) 会被乘进关于 \(y\) 为半径的贡献里面。
位运算卷积
大概是和 FWT 结合相关,你可以看成是 FWT 拓展。希望可以从更加深刻的角度解读这档子事情。考虑这里运用到了容斥系数(?)所以将要记录在这里。我们推导式子的目标
\(f_S = \sum\limits_{T}g_{S\cup T}h_T \\ = \sum\limits_{S\subset T} g_T\sum\limits_{W\cup S = T}h_W\)
P11458
不是 11451 差评
丁真告诉我们我们很希望能够计算每一位的贡献,试试看从这里入手?
如果没有分母,只有分子,那么对每一位计算贡献是容易的。如果只有分母,没有分子,你发现这挺难的。并且你显然是不能直接做的。这个东西会让你想到 fwt 之类的东东
min-max 容斥
感觉很牛的样子:对于集合里面的元素,有
很牛的一点在于它在期望下仍然成立:
看看应用,感觉不太多。
P3175
一个超级 naive 的想法:对于每个节点作为一个二进制数建点,然后向外有概率游走,最后求从 \(0\) 点游走到 \((2^n - 1)\) 点的期望。注意到这不是一张 DAG 可能会有不少的向自己的连边,常用的手法是高斯消元,然后就跑不过去了。
从正面硬刚中解脱一下换一个思路,考虑到这是位运算所以按位考虑。最后一个 \(1\) 出现时间的期望就是答案,根据 min-max 容斥可以变成 \(S\) 内第一个 \(1\) 出现的时间的期望。这个会好做很多,因为限制很好刻画。如果是第 \(k\) 次出现说明前 \((k-1)\) 次出现都是 \((U - S)\) 子集,这样的期望满足几何分布,是 \(\dfrac{1}{p}\),\(p\) 用高维前缀和计算即可。
杂题
有难有易,当个乐子。
有些也可以看作是上面的练习题喔。
arc121_e
条件是不允许出现 \(a_i\) 作为 \(i\) 的祖先。
不允许是一个难以刻画的条件,但是允许是很容易的,不难想到容斥正难则反,钦定不合法的数目,令不合法数为 \(x\) 容斥系数则为 \((-1)^x\)。为了把全部内容压缩到一个子树里面 dp,我们令 \(f[u, k]\) 为子树内钦定 \(k\) 个对不合法的方案数。\(f\) 随便 dp。
P8329
神。无法战胜。我是龙。一只奶龙。
观察一下题目
- 首先看上去就不是一个性质题。
- 可以考虑钦定 \(T1\) 中叶子集合,分别计算 \(T1,T2\) 的方案数,拼起来。
- 注意到钦定 \(S\) 内为叶子很好计算,但是恰好需要子集反演。
然后直接列式子。
下标代表树,我们设 \(f_{1, 2}(S)\) 为钦定 \(S\) 内为叶子。\(g_{1, 2}(S)\) 为恰好 \(S\) 内为叶子,直接列式子:
最后那个和式可以直接计算吗?
通过你的眼睛,显然存在
\(A\cap B \not= \empty\) 时最后的求和式显然为 \(0\),当 \(A\cap B = \empty\) 时,最后的求和式又显然为 \((-2)^{n - |A| - |B|}\)。所以答案就是
增量加入每个点考虑在 \(A\),\(B\) 或者都不在即可。直接计算 \(f_1(A), f_2(B)\) 很简单所以这个也比较简单。主要难点在于对式子的操作。这里为什么我自己没有想到?一开始我以为是因为我直接用 \(U - S = T\) 导致我的式子不能看走向了奇怪的道路。这显然不是一个原因。我觉得是因为我没有想好这个式子最后到一个什么形式才能做。这里式子化简的动机还是比较明确的,最后一定是系数和 \(f_1(C)f_2(D)\) 的求和。那么对于这个乘积考虑系数也是很自然的。然后就能把这题做出来。
P5825
感觉这题真的很牛啊。我被一开始的刻画击杀了。拜谢 Little09
这道题首先一开始我的想法是直接 dp 然后 ogf,但是我蹩脚的 ogf 就被狠狠的肘飞了,就很坏。
随后自然的我们会考虑到二项式反演状物上面来(恰好,并且位置之间看上去很等价)。如何计数“钦定有 \(k\) 个位置上升”的方案数?我一开始想的是把上升段落看作一个联通块,那么这个问题就变成了一个很麻烦的计数,然后我就破防了不会推。确实很难推把,如果有人能薄纱这档子事情请私信我我一定会学习的 qaq
但是 little09 教育我门可以反过来看待这件事情,上升段保护,下降段全部断开。硬说动机我觉得可能和点减边容斥有点相似,\(n\) 个点,钦定 \(k\) 个位置上升相当于连接了 \(k\) 条边,最后剩下了 \((n - k)\) 个联通块,联通块内部全部是上升的方案唯一,联通块之间任意。联通块自身不能为空,实际上是第二类斯特林数,具体化简放到第二类斯特林数中(也可以容斥),这里提出来是因为我觉得它利用的这个刻画手法很巧妙,我们并不关心具体结构,只关心联通块数量。这可能也在启发我们用更加简洁的手法刻画。
P13275
哈集幂哈集幂哈集幂哈集幂哈集幂哈集幂哈集幂哈集幂哈集幂哈集幂哈集幂哈集幂哈集幂哈集幂
首先这道题我往一维的子集反演想了很久,这是很大的错误,应该在想不出来第一时间去考虑二维子集反演。设 \(F(S, T)\) 为 \(f(P)\) 为 \(S\) 超集,\(f(Q)\) 为 \(T\) 超集,\(g(S, T)\) 为恰好为 \((S, T)\) 的答案,那么二维子集反演得到
到这一步应该是相当 trivial 的(虽然我也想了很久)。考虑后面这部分 \(F(T_1, T_2)\) 如何快速计算,这里我没有想到,因为我想的是直接算,整点高维前缀和,没有想到容斥状物(可恶这里怎么还要容斥有完没完了火大大) 。注意到实际提供贡献的只有 \((1+a_i)\) 和 \((1+2a_i)\) 两种,\([T_1 \subseteq i] + [T_2 \subseteq i]\) 分别讨论,等于 \(2\) 那么就是 \([T_1\cup T_2\subseteq i] = 1\),这一部分全部提供 \((1+2a_i)\)。那么前一个部分我们就可以考虑一些很容斥的东西,设 \(f_{S}\) 为 \(\sum\limits_{S\subseteq i}(1+a_i)\), \(g_S\) 为 \(\sum\limits_{S\subseteq i}\dfrac{(1+2a_i)}{(1+a_i)^2}\),最后有
\(h\) 为一个或卷积,直接 FWT 即可,\(g\) 直接计算即可。时间复杂度 \(O(n2^n)\)。注意到可怕的一点在于我们可能出现 \((1+a_i) = 0\) 的情况(性质 B 会提醒我们)怎么办?题解区里面学到了,考虑扩域,我们的 \(f, g, h\) 从整数域扩充到新的域,记录 \((v, k)\) 意思为 \(v\times 0^k\)。对于加法 \(k\) 小的加,\(k\) 相等那么就都加,乘法合并 \(k\) 直接相加,减法 \((v_1, k_1) - (v_2, k_2)\) 只有 ifwt 过程中涉及,\(k_1 \le k_2\)。如果 \(k_1 < k_2\) 那么没有贡献。
P10004
牛的,学习。
显然的二项式反演,考虑钦定 \(x, y\) 个位置。做过 P5825 的小朋友们都知道,没有对逆排列的要求,对于原排列可以把一个钦定看作一条边,没有逆排列要求也就是说 \((n - x)\) 个联通块,联通块内有序,这是经典的第二类斯特林数,也可以用容斥来算。
现在考虑逆排列的要求。我们无法使用比较好的结构(如置换群,置换环)在刻画逆排序的时候顺手维护 \(p^{-1}_i < p^{-1}_{i+1}\),所以还是要分析性质。这里面我们可以首先考虑钦定 \(x\) 个位置实际上对于排列的影响,再考虑对逆排列的影响。
钦定 \(x\) 位置形成 \((n - x)\) 个上升联通块,块块之间独立,联通块内部上升。放到逆排序中去就会得到一段值域在 \([l, r]\) 内的上升子序列。将联通块从左到右加入逆排序,实则是往逆排序的空位里面插入了 \((n - x)\) 个上升子序列。
接下来是我没有办法想到的地方了。
我们可以强制规定好原串中 \((n - x)\) 个连续段区间和 \((n - y)\) 个逆排列中的连续段区间。强制要求将原串中的连续段从左到右加入 \((n - y)\) 个逆排列区间中,要求是:
- 首先对于一个原连续段,和每个逆排列连续段最多只有一个连续段交。
- 每次交一定是紧贴着上一次的连续构造出来的。
到了这一步构造出这样一种双射关系也就不难了:对于每一个这样的钦定关系,进行 \((n - x)\) 次分配,每次分配 \(l_i\) 个数,这些数将要分给 \((n - y)\) 个堆里面,一个堆在一个 \(l_i\) 只能分配一次。要求是每次 \(l_i> 0\),最后每个堆都有数。放到矩阵里面相当于一个 \((n - x)\times (n - y)\) 的矩阵,每个位置可以填一个数,要求每一行每一列和都大于 \(0\),并且最后总和为 \(n\)。
设 \(g(x, y)\) 为一个 \(x\times y\) 满足上述条件的矩阵,那么考虑二维二项式反演。钦定 \(i\) 行和 \(j\) 列为 \(0\),那么:
容易优化到 \(O(n^3)\)。