容斥技术(长期更新)

容斥的最直接的想法就是给算重了的东西填上系数,使得不合法的东西都算了\(0\)次,然后合法的东西都算了\(c\)次(\(c\)为常数,\(c=1\)当然最好)。

要证明一种容斥是对的,就考察任意一个对象,验证其计数次数是否符合要求即可。

普通容斥

对于一个集合 \(S\) 的一部分子集构成的簇 \(P\) 有:

\[\lvert \bigcup_{T \in P} T\rvert=\sum_{Q \subseteq P} (-1)^{|Q|-1} \lvert \bigcap_{T \in Q} T \rvert \]

证:

设元素 \(x\)\(k(k \ne 0)\)\(S\) 的子集中被包含,则它对左式的贡献为 \(1\)。现在来看它对右式的贡献,为:

\[\begin{aligned} \sum \limits_{i=1}^k (-1)^{i-1} {k \choose i}&=(-1) \times \sum \limits_{i=1}^k (-1)^i {k \choose i}\\ &=1-(-1) \times \sum \limits_{i=0}^k (-1)^i {k \choose i}\\ &=1+(1-1)^k\\ &=1 \end{aligned} \]

\(i\) 相当于在枚举 \(\lvert Q \rvert\) 的大小。

所以原式得证。

最为简单的容斥就是正难则反的思想,用不考虑任何限制的减去有限制的,有的时候有限制的可以直接算了就不用继续想了。

二项式反演似乎是很常用的容斥技巧,但是已经把它放在反演里面了,就不单独说了。毕竟二项式反演已经告诉了我们应该使用哪种系数,所以是简单的。

各种反演也是常用的容斥手段,相当于已经知道系数的容斥。

介绍一种将容斥与生成函数相结合的思想,这使得容斥的含金量还在上升。

以下内容纯属口胡,可能不太正确,不太完整。


首先我们可以对要计数的对象搞一个生成函数\(G\)出来,然后又记容斥系数的生成函数为\(F\)

于是最终就是\(F\)通过运算得到\(G\),然后就可以尝试反解出\(F\),就得到了容斥系数。

这样做应该就不用猜测容斥系数了(?)。

更一般的凑容斥系数的方法

考虑要计数恰好\(k\)种集合覆盖的元素贡献为\(f_k\)大小\(s\)的集合的容斥系数为\(g_s\)

那么就有\(\sum\limits_{1\le i\le k} \dbinom{k}{i} g_i=f_k\)

\(g_0=0\),那么\(\sum\limits_{0\le i\le k} \dbinom{k}{i} g_i=f_k\)

反演一下得到\(g_k=\sum\limits_{0\le i\le k}(-1)^{k-i}\dbinom{k}{i} f_i\)

Min-Max 容斥

式子:

\[\begin{aligned} \max S&=\sum \limits_{T \subseteq S} (-1)^{\lvert T \rvert -1} \min T\\ \max \limits_{kth} S&=\sum \limits_{T \subseteq S} (-1)^{\lvert T \rvert -k} {\lvert T \rvert -1 \choose k -1} \min T \end{aligned} \]

以上两个式子把 \(\min ,\max\) 对换也是成立的,即:

\[\begin{aligned} \min S&=\sum \limits_{T \subseteq S} (-1)^{\lvert T \rvert -1} \max T\\ \min \limits_{kth} S&=\sum \limits_{T \subseteq S} (-1)^{\lvert T \rvert -k} {\lvert T \rvert -1 \choose k -1} \max T \end{aligned} \]

这个东西好用是因为可以直接在上面套期望。然后做期望DP来求。

反射容斥

用于格路计数问题,可以在转移与格路计数类似的DP中见到,然后直接用数学方法优化。

首先容易得到\((x_0,y_0)\)关于\(y=x+b\)对称得到\((y_0-b,x_0+b)\)

以及\((0,0)\)走到\((n,m)\)的方案数为\(\binom {n+m}n\)

先来考虑一下Catalan数的格路计数的推导方式解决一个类似的问题,这里我们不能经过\(y=x+1\),从\((0,0)\)走到\((n,m)\)

我们对每一种经过了\(y=x+1\)的非法路线沿\(y=x+1\)翻折,每一种非法路线的终点都是\((m-1,n+1)\),可以简单证明\((0,0)\)走到\((m-1,n+1)\)的路线一一对应着一条非法路线。于是\(C_n=\binom {n+m}n-\binom {n+m}{n+1}\)

于是不能经过一条直线的格路计数问题已经解决了。现在来考虑不能经过两条直线的情况。解决了两条直线的情况,我们就已经知道了格路计数中不能经过\(k\)条直线的全部,因为只需要取距离\(y=x\)最近的两条直线即可。

两条直线在同侧的情况已经解决了,这里考虑两条直线\(y_1=x+l\)\(y_2=x+r\)\(l<0<r\),当然要异侧)。

我们记\(L\)表示经过了\(y_1\)一次,\(R\)表示经过了\(y_2\)一次,若连续多次经过同一条直线,我们只在其第一次经过时记录一次。于是将当前折线经过的直线的字母写下来,就是\(S=LRLR\dots\)或者\(RLRL\dots\)或者\(\varnothing\)

我们记\(f(S)\)表示\(S\)作为一个子序列出现过的所有路径的方案数。

那么有结论:从\((0,0)\)走到\((n,m)\)的方案数\(ans=f(\varnothing)+\sum\limits_{k\ge 1,k=|s|}(-1)^k\Big(f(LRLR\dots)+f(RLRL\dots)\Big)\)

证明是这样的,考虑一个串\(S=LRLR\dots\)(不失一般性,不妨以\(L\)开头)被计数了几次(应该是\(0\)次)。空集贡献了\(1\)。是\(S\)的子序列的串就是\(S\)的每个前缀以及\(S\)去掉第一个字符后的串的每个前缀。前一种的贡献是\(\sum\limits_{k=1}^{|S|}(-1)^k\),后一种的贡献为\(\sum\limits_{k=1}^{|S|-1}(-1)^k=(-1)\times \sum\limits_{k=2}^{|S|}(-1)^k\),两个加起来就是\(-1\),再算上空集的贡献就是\(0\)。于是对于\(S\neq \varnothing\)的都只算了\(0\)次,所以是对的。

然后又怎么算呢?发现\(f(S)\)是好算的,设\((n,m)\)经过\(S\)中的翻折(类似反射?)到了\((n',m')\),那么\(f(S)=\binom {n'+m'}{n'}\)

先把\(ans\)的前几项写开:

\(ans=\binom {n+m}n-\binom{n+m}{n+l}-\binom{n+m}{n+r}+\binom{n+m}{n+l-r}+\binom{n+m}{n-l+r}-\binom{n+m}{n+2l-r}-\binom{n+m}{n-l+2r}+\binom{n+m}{n+2l-2r}\dots\)

大力观察可以发现,我们不要原来的那个求和号,直接拆开,然后每四个为一组来看,第一个与第三个配对,第二个与第四个配对,可以得到更容易计算的柿子:

\[ans=\sum\limits_{k\in\mathbb{Z}}\binom{n+m}{n-k(r-l)}-\binom{n+m}{n-k(r-l)+r} \]

注意到随着\(k\)增大,下指标到负数就全为\(0\)了,所以可以预处理\(O(\dfrac{n}{r-l})\)个组合数,然后\(O(n)\)去算。

其实最终的难点不在于使用反射容斥,而是中间的转化。

例题

P3266 [JLOI2015] 骗我呢

简要题意:\(n\times m\)的格子,每个格子中有\(0\le X_{i,j}\le m\)。满足\(X_{i,j}<X_{i,j+1}\land X_{i,j}<X_{i-1,j+1}\)。现在来填这个格子,有多少种方案数?

Sol:

首先来想朴素DP。发现一行中数字两两互不相同,一行有\(m\)个数要填,而值域为\([0,m]\)一共\(m+1\)个数。这个性质很好,可以设DP状态为\(f_{i,j}\)表示填到了第\(i\)行,第\(i\)行没有填\(j\)的方案数。

然后手推一下,发现上一行要是没有填\(>j+1\)的数,第\(i\)行就一定会填\(j\)。于是转移就是\(f_{i,j}=\sum\limits_{k=0}^{j+1} f_{i-1,k}\)

再化一步,注意到有点像前缀和的形式,可以化出\(f_{i,j}=f_{i,j-1}+f_{i-1,j+1}\)\(j\neq 0\)),\(j=0\)时,\(f_{i,j}=f_{i-1,j}+f_{i-1,j+1}\)\(i=1\)时,\(f_{i,j}=1\)

然后这是二维的DP,发现形式很像在格路上统计路径数量。于是把图手画一下。注意\(j=0\)处有格外的边。由于有斜着的边,于是把每行平移一点,总之可以转化到从\((0,0)\)走到\((n,n+m+1)\),不经过\(y_1=x-1\)\(y_2=x+m+2\)的方案数,上反射容斥就做完了。

发现反射容斥可以把看起来像格路计数的DP柿子直接\(O(n)\)算。

参考:大佬的容斥博客

符号化容斥

ref:

cmd的博客

yspm的博客

cyffff的博客

似乎和序列上的集合划分容斥高度相关,或许可以试着将形式幂级数换成集合幂级数然后搞一搞,推荐cyffff的博客

利用类似符号化方法的思想,考察容斥系数的生成函数。推荐yspm的博客

基本思路是,考察一个基本单位的组合类\(\mathcal F\),要去求它在某种限制下的组合\(\text{COMB}_{\text{R}} (\mathcal F)\)

可以考虑扩充基本单位的组合类\(\mathcal F\),得到\(\mathcal F^*=\mathcal F+\mathcal I\),使得\(\mathcal F^*\)\(\mathcal F\)\(\text{COMB}\)的构造下得到同一种组合对象,这里不用管方案数是否相同,因为后面有\(\text{COMB}(\mathcal F^*)=\text{COMB}_{\text{R}}(\mathcal F)\)。同时要构造\(\mathcal F^*\)上每一个元素的贡献,使得\(\text{COMB}(\mathcal F^*)=\text{COMB}_{\text{R}}(F)\),来去掉\(\text{R}\)的限制。

这里\(\mathcal F^*\)上的每一个元素的贡献或许可以理解为容斥系数,而为了在组合类和生成函数的双重视角下切换,我们认为,容斥系数\(f_i\)就是大小为\(i\)的元素在组合类中的个数,虽然\(f_i\)可能小于\(0\)

从组合类转化到生成函数时,我们只关注生成函数中占位元的指数和系数,对应到组合类中,即元素的大小和数量,而不必去关注元素的具体形态。

\(\mathcal L\)中的每种元素,我们认为其数量为\(1\),即容斥系数为\(1\)

那么这里我们的容斥系数潜藏在组合类与生成函数之间,不妨称之为符号化容斥。

接着上面的思路,我们再设\(\mathcal L\)表示满足限制的基本单位的组合类,这个一般是易知的,我们需要尝试将\(\mathcal F^*\)或者\(\mathcal I\)\(\mathcal L\)建立一个符号方程,进而导出生成函数上的关系。

注意,用于扩充基本单位的组合类\(I\)可能与原来的基本单位组合类\(\mathcal F\)有以下关系:

  • 无交

  • 有交但不包含

  • 包含

一般来说,通过处理一下它们之间的关系使得它们无交后(比如包含时直接合并,有交时把交集归到一遍),后续处理会好做一些。

关于建立符号方程,我们可以对\(\mathcal F^*\)或者\(\mathcal I\)进行构造,并使结果为\(\mathcal L\),这样做是为了去掉\(\text{R}\)的限制。

而且这里在对\(\mathcal I\)进行构造前,我们会把所有可能超出限制的元素都扔到\(I\)里面,剩在原来的\(\mathcal F\)中的元素一定是如何构造都不会超出限制的。


以上说得乱七八糟的,引用看到的一份形式化描述:

在某种等价关系下,对于某一特定的组合结构,构成它的元素可以被划分为若干等价类,有一个关于等价类的函数\(F(\mathcal A)\)(用来描述这个等价类中元素的贡献系数)。而现在在我们简单的构造中不能恰好刻画出每一个极大的等价类,记等价类之间的合并关系为\(G(\mathcal A)\),我们要设计容斥系数\(H(\mathcal A)\)满足:

\[G(H(\mathcal A))=F(\mathcal A) \]

那这里的\(F(\mathcal A)\)就相当于上述的\(\mathcal L\)所发挥的作用,\(G(\mathcal A)\)就相当于组合类之间的构造关系,\(H(\mathcal A)\)就相当于上述可能超出限制的元素在组合类中应该带的系数(或者叫做数量)。

这里只是求出了容斥系数,进一步的求解还需具体分析。

posted @ 2024-12-14 16:08  RandomShuffle  阅读(226)  评论(2)    收藏  举报