\(\S1.\) 等价容斥

  (乱取的名字.)

  题目将组合对象构成的 "等价类" 进行了定义和限定. 我们往往无法计数 "等价类真的长这样" 的方案, 而只能求出 "钦定等价类长这样, 但不能保证等价类间不等价" 的方案. 这个时候就可以用「等价容斥」求出最终答案.

  形式化地, 设题目要求每种等价类对答案的贡献系数构成关于等价类大小的 GF \(C(x)\), 那么我们设单个等价类的容斥系数为 \(G(x)\), 多个被钦定的等价类的合并规则遵从表达式 \(f(G)\), 并希望它们满足

\[C(x)=f(G(x)).
\]

  这里 \(f\) 通常比较简单, 于是能找到 \(G\) 的简介表达. 之后在钦定等价类时, 为大小为 \(k\) 的等价类带上 \([x^k]G(x)\) 的容斥系数, 组合时容斥系数求乘积, 就能得到最终的答案.

  如果继续扯下去真的玄虚之至了, 我们来看点具体的例子.

  \(\textbf{Example 1.1.}\) 「洛谷 P7275」计数Link & Submission.

  \(\textbf{Solution.}\) 考虑一棵合法的树, 其必然能被唯一地剖分为若干条长度 \(>1\) 的树链, 每条树链的结点编号对应一个区间. 反过来, 我们可以先将 \([1,n]\) 划分为若干区间, 再用边将它们连起来, 同时保证不会让两个区间合并.

  "不会合并" 这个限制比较麻烦, 先把它扔掉, 此后连接区间的方案数可以用 Prufer 算. 令 \(f(i,j)\) 表示把 \([1,i]\) 划分为长度为 \(l_{1..j}\) 共 \(j\) 段时 \(n^j\prod_{k}l_k\) 之和. 考虑等价容斥, 令 \([x^l]G(x)\) 表示长为 \(l\) 的区间的容斥系数, 那么 \(l\) 的容斥系数总贡献为

\[c_l=[x^l]\sum_{i\ge 1}G^i(x)=[x^l]\left(\frac{1}{1-G(x)}-1\right).
\]

我们希望 \(c_l=[l>1]\), 于是

\[\frac{1}{1-G(x)}-1=\frac{x^2}{1-x}\\
\Rightarrow G(x)=\frac{x^2}{x^2-x+1}.
\]

手算一下系数, 发现

\[\operatorname{SEQ} G(x)=\lang0,0\rang\lang1,1,0,-1,-1,0\rang^{+\infty}.
\]

  于是, 单个区间的 OGF \(H(x)\) 为

\[H(x)=\sum_{i}ni\cdot [x^i]G(x).
\]

欲求的 \(f(n,i)\) 为

\[f(n,i)=[x^n]H^i(x).
\]

最后

\[\begin{aligned}
\textit{ans} &= n^{-2}\sum_{i}[x^n]H^i(x)\\
&= n^{-2}[x^n]\frac{1}{1-H(x)}.
\end{aligned}
\]

  直接多项式可以做到 \(\mathcal O(n\log n)\). 当然可以发现这是个线性递推求远项, 所以也能 \(\mathcal O(\log n)\).

  \(\textbf{Example 1.2.}\) jiangly 的排列数数题 给定 \(n\), 对于每个 \(k\), 求有多少个 \(n\) 阶排列含有至少一个长度为 \(k\) 的上升段. 也许 \(n\le2\times10^3\)?

  \(\textbf{Solution.}\) 容斥成 "不含". 固定 \(k\), 令 \(G_k(x)\) 为容斥系数, 与上题类似地有

\[\frac{1}{1-G_k(x)}-1=\frac{x-x^k}{1-x}\\
\Rightarrow G_k(x)=\frac{1-x}{1-x^k}.
\]

答案:

\[\textit{ans}=n![x^n]\frac{1}{1-\sum_i g_i/i!\cdot x^i}.
\]

注意 \(G_k(x)\) 只有 \(\mathcal O(n/k)\) 项, 暴力求逆 \(\mathcal O(n^2/k)\), 总共 \(\mathcal O(n^2\log n)\). EI 提出了更厉害的优化.

  \(\textbf{Example 1.3.}\) 「LOJ #6728」U 群把妹王Link & Submission.

  \(\textbf{Solution.}\) 来容斥. 令 \(R(x)\) 表示行上容斥系数的 EGF, 那么

\[\exp R(x)-1=\sum_{i\in S}\frac{x^i}{i!}\\
\Rightarrow R(x)=\ln\left(1+\sum_{i\in S}\frac{x^i}{i!}\right).
\]

  选行, 令 \(f_i=[x^i]F(x)\) 表示把 \(n\) 行钦定为 \(i\) 个等价类 (等价类间可能存在等价关系) 的方案数, 那么

\[f_i=\frac{n!}{i!}[x^n]R^i(x).
\]

选列, \(C(x),g_i=[x^i]G(x)\) 类似. 最终答案为

\[\begin{aligned}
\textit{ans}
&= \sum_{i,j}f_ig_jk^{ij}\\
&= \sum_{i,j}f_ig_jk^{\binom{i+j}{2}-\binom{i}{2}-\binom{j}{2}}.
\end{aligned}
\]

  答案倒是好算, 问题是 \(f,g\) 比较麻烦. 注意到

\[F(z)=n![x^n]\exp zR(x).
\]

(注意 \(F(z)\) 是 OGF 而非 EGF.) 因为 \(|S|\) 较小, 所以牛迭可以 \(\mathcal O(|S|n\log n)\) 求出 \(R(x)\) 的复合逆 \(P(x)\). 大概是解这么一个方程:

\[p(u,x)=x-\ln\left(1+\sum_{i\in S}\frac{u^i}{i!}\right)=0,\\
\begin{aligned}
u_{2n}
&\equiv u_n-\frac{p(u_n,x)}{p_u(u_n,x)}\\
&\equiv u_n+\frac{(x-\ln S(u_n))S(u_n)}{S'(u_n)}\pmod{x^{2n}}.
\end{aligned}
\]

最后套拉反:

\[[x^n]\exp zR(x)=\frac{1}{n}[x^{n-1}]ze^{zx}\left(\frac{x}{P(x)}\right)^n.
\]

多项式瞎算即可. \(\mathcal O(an\log n+bm\log m)\), 常数巨大.

\(\S2.\) 反射容斥

  (名字是别人取的.)

  双限制的走折线问题. 即求从 \((0,0)\) 走到 \((n,m)\), 每步位移为 \((1,\pm1)\), 且不能碰到 \(l_1:y=a\) 和 \(l_2:y=b~(a<0<b)\) 的方案数.

  我会做只有 \(l:y=b\)! 答案是 \([(0,0)\rightarrow(n,m)]-[(0,0)\rightarrow(n,2b-m)]\). 这里只对第一次碰到 \(l\) 的地方进行了 "反射".

  现在有 \(l_1,l_2\), 给出结论, 合法方案数为: 「总方案」\(-\)「撞 \(l_1\) 的方案」\(-\)「撞 \(l_2\) 的方案」\(+\)「撞 \(l_1l_2\) 的方案」\(+\)「撞 \(l_2l_1\) 的方案」\(-\)「撞 \(l_1l_2l_1\) 的方案」\(-\)「撞 \(l_2l_1l_2\) 的方案」\(+\cdots\) 注意 "撞" 是指第一次迎面撞上 ("撞上" 前在合法位置).

  如何计数呢? 以「撞 \(l_1l_2l_1l_2\) 的方案」为例, 类似于 \(l:y=b\) 的情况, 我们将终点 \((n,m)\) 依次沿 \(l_2,l_1,l_2,l_1\) 翻折到 \(P\), 计算方案 \((0,0)\rightarrow P\). 注意我们容斥的是撞击点的一段后缀, 所以对于任意非空撞击序列, 其从 \(l_1\) 开始翻和从 \(l_2\) 开始翻必然会被 \(\pm1\) 共计数次, 实际上刚好就是 \(-1\). 所以这个容斥很正确. 最后我们就只需要计算 \(\mathcal O(n/(|a|+|b|))\) 个组合数.

  组合意义会引起不安吗 ... 那我们来欣赏一下代数推导. 这里先固定 \(l_1:y=-1\), 也就是经典的 Catalan 数形式. 考虑数轴上的行走, 每步位移为 \(\pm1\). 记从 \(0\) 走到 \(t\) 步到 \(x\), 中途不经过 \(-1\) 的方案数为 \(q_{x,t}\). 我们知道谜底, 但看破不说破.

  考虑暴力地把问题塞进 GF 这个袋子里, 令 \(Q(x,t)=\sum q_{x,t}x^it^j\). 容易列出方程

\[Q(x,t)=1+(x+x^{-1})tQ(x,t)-x^{-1}tQ(0,t).
\]

整理一下:

\[(1-(x+x^{-1})t)\cdot xQ(x,t)=x-tQ(0,t).
\]

代入 \(x\gets x^{-1}\):

\[(1-(x+x^{-1})t)\cdot x^{-1}Q(x^{-1},t)=x^{-1}-tQ(0,t).
\]

上下作差:

\[xQ(x,t)-x^{-1}Q(x^{-1},t)=\frac{x-x^{-1}}{1-(x+x^{-1})t}.
\]

观察系数位置, 可知

\[Q(x,t)=\frac{1-x^{-2}}{1-(x+x^{-1})t}-R(x),
\]

其中 \(R(x)\) 的系数仅出现与负指标, 提取 \(Q(x,t)\) 的非负指标位置系数时可忽略. 考察提取过程

\[\begin{aligned}[]
[x^nt^m]\frac{1-x^2}{1-(x+x^{-1})t}
&=[x^n](1-x^2)(x+x^{-1})^m\\
&=[n\equiv m\pmod2]\left(\binom{m}{\frac{n+m}{2}}-\binom{m}{\frac{n+m}{2}+1}\right).
\end{aligned}
\]

  我尝试用类似方法推导双限制的反射容斥, 败北了. 可能还是得使用 EI 败北后的反击方法.

  \(\textbf{Example 2.1.}\) 「UOJ #424」countLink.

  \(\textbf{Solution.}\) 只需要讨论 \(n\ge m\) 的情况. 我们可以通过多叉笛卡尔树唯一确定 \(f\). 众所周知, 设树 \(T\) 的树根为 \(r\), 其儿子 \(u_{1..k}\), 那么我们存在 \(T\mapsto S\in\{\texttt(,\texttt)\}^{2(|T|-1)}\) 的单射. 即构造

\[\operatorname{SEQ}(r)=\texttt(\operatorname{SEQ}(u_1)\texttt)\texttt(\operatorname{SEQ}(u_2)\texttt)\cdots.
\]

所以只需要对这样的序列计数.

  如何保证仅仅使用 \([1,m]\) 中的整数? 显然就是要求树高 (叶子到根进过的最多边数) 不超过 \(m\). 对应到括号序列上, 也就是前缀 \(\texttt(~-\) 前缀 \(\texttt)\) 恒 \(\le m\), 当然这个差值也应该恒 \(\ge0\). 令 \(l_1:y=-1,l_2:y=m+1\), 我们就得到了标准的反射容斥问题. 当然你可以用 GF, 不过容易败北.

  \(\textbf{Example 2.2.}\) 求含 \(n\) 个 \(1\), \(m\) 个 \(0\) 的序列, 使得任意区间包含 \(01\) 个数差不超过 \(k\). \(n,m,k\le5\times10^7\).

  \(\textbf{Solution.}\) 从 \((0,0)\) 走到 \((n+m,n-m)\), 任意两点高度差不超过 \(k\). 实际上只需要最高点与最低点高度差不超过 \(k\). 枚举最低高度 \(a\), 容斥求出最低恰为 \(a\), 最高不超过 \(k-a\) 的方案数, 这一步是 \(\mathcal O((n+m)/k)\) 的. \(a\) 只有 \(k\) 种, 所以复杂度 \(\mathcal O(n+m)\).

Note - 两类容斥的更多相关文章

  1. bzoj4767两双手 容斥+组合

    4767: 两双手 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 684  Solved: 208[Submit][Status][Discuss] ...

  2. 2019.02.11 bzoj4767: 两双手(组合数学+容斥dp)

    传送门 题意简述:你要从(0,0)(0,0)(0,0)走到(ex,ey)(ex,ey)(ex,ey),每次可以从(x,y)(x,y)(x,y)走到(x+ax,y+ay)(x+ax,y+ay)(x+ax ...

  3. BZOJ.4767.两双手(组合 容斥 DP)

    题目链接 \(Description\) 棋盘上\((0,0)\)处有一个棋子.棋子只有两种走法,分别对应向量\((A_x,A_y),(B_x,B_y)\).同时棋盘上有\(n\)个障碍点\((x_i ...

  4. hdu 5072 两两(不)互质个数逆向+容斥

    http://acm.hdu.edu.cn/showproblem.php?pid=5072 求n个不同的数(<=1e5)中有多少组三元组(a, b, c)两两不互质或者两两互质. 逆向求解,把 ...

  5. 【BZOJ】4767: 两双手【组合数学】【容斥】【DP】

    4767: 两双手 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1057  Solved: 318[Submit][Status][Discuss] ...

  6. 【BZOJ4767】两双手(动态规划,容斥)

    [BZOJ4767]两双手(动态规划,容斥) 题面 BZOJ 题解 发现走法只有两种,并且两维坐标都要走到对应的位置去. 显然对于每个确定的点,最多只有一种固定的跳跃次数能够到达这个点. 首先对于每个 ...

  7. HDU 5794 A Simple Chess (容斥+DP+Lucas)

    A Simple Chess 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5794 Description There is a n×m board ...

  8. How Many Sets I(容斥定理)

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3556 How Many Sets I Time Limit: 2 ...

  9. bzoj 2669 [cqoi2012]局部极小值 DP+容斥

    2669: [cqoi2012]局部极小值 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 838  Solved: 444[Submit][Status ...

  10. 【容斥原理,莫比乌斯反演】用容斥替代莫比乌斯反演第二种形式解决gcd统计问题

    名字虽然很长.但是其实很简单,对于这一类问题基本上就是看你能不能把统计的公式搞出来(这时候需要一个会推公式的队友) 来源于某次cf的一道题,盼望上紫的我让潘学姐帮我代打一道题,她看了看跟我说了题解,用 ...

随机推荐

  1. 文件操作(C语言)

    1. 为什么使用文件? 如果没有文件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运行程序,是看不到上次程序的数据的,如果要将数据进行持久化的保存,我们可以使用 ...

  2. C语言实战项目——学生试卷分数统计

    1.题目要求 作为教师,考试以后对试卷进行分析和研究是必须做的一项工作,假定某学校要求老师在考试之后填写的一个表格,并要求教师根据考试分数分布情况画出直方图.下面就来解决这个实际问题. 2.题目分析 ...

  3. WPS Excel中配置下拉多选(VBA)

    网上找到两种方案,一种利用数据选择其他单元格,也就是在其他单元格建数据.需求是模板,不合适 这里我用的VBA,踩了挺多坑,详细说下 首先更新WPS为最新版,确保可用VBA和JSA 确定使用VBA还是J ...

  4. 如果让你处理hbase 怎么保证数据的安全性可靠性 不需要具体的设置 要一套方案

    有关数据安全及可靠我们认为大体上分为存储安全和使用安全 1 数据存储安全 hbase是基于hdfs的一种数据存储解决方案,所以有关数据的安全性可靠性可以利用hdfs自身的副本机制保障.另外原生的hba ...

  5. pdf.js使用

    百度上很多例子,都是构建之前的! 我们使用pdf.js,最终只需要构建后的内容,大家可以通过这里进行下载: https://pan.baidu.com/s/14J-m-jeHdvn46cPhPXk54 ...

  6. Python之subprocess 执行报错

    问题 我用subprocess 执行命令查 主机Ip 报错 ​ command = """ "grep {0} /etc/hosts | awk '{print ...

  7. php xattr操作文件扩展属性

    观摩了这篇文章后https://www.cnblogs.com/zyblog-coder/p/15013804.html 学到了php还有操作文件扩展属性的扩展 快速安装了一下 sudo apt-ge ...

  8. canvas 隐写术

    http://www.alloyteam.com/2016/03/image-steganography/#prettyPhoto https://www.cnblogs.com/Miracle-ZL ...

  9. 在matlab中使用遗传算法执行最优化

    遗传算法是一种通用的最优化方法,具体原理可以看:遗传算法详解与实验.下面记录在Matlab中如何使用遗传算法来做优化. 用法 调用方式如下: 1 x = ga(fun,nvars) 2 x = ga( ...

  10. golang之浮点数处理库decimal

    decimal库包是用来解决float类型对象之间运算不准确的问题的.所以,如果你想使用decimal库包,你必须先把float类型对象通过decimal.NewFromFloat()函数转成deci ...