容斥与反演技巧(一)

其实 2022.9.27 就发布了

二项式反演

我们直接上式子好了

一般有两种形式,第一种是

f(n)=i=0n(ni)g(i)g(n)=i=0n(1)ni(ni)f(i)

第二种是

f(n)=i=nm(in)g(i)g(n)=i=nm(in)(1)inf(i)

第二种比第一种更加常用。

一般来说我们的 f(n) 是钦定 n 个元素必须选中,剩下的随便选的方案数。注意 f 并非单纯的后缀和。

例题

球的染色

n 个球排成一列,每个球可以染成 m 种颜色,相邻球的颜色不能相同,但是每种颜色至少出现一次,问方案数。

如果没有至少出现一次的限制那么答案就是 m×(m1)n1

考虑转化为 恰好有 0 个颜色没有出现过,那么设 f(k) 为钦定某 k 种颜色没有出现的方案数,那么 f(k)=(mk)×(mk1)n1

g(k) 为恰好 k 个颜色没有出现过的方案数,那么

f(k)=i=km(ik)g(i)g(k)=i=km(1)ik(ik)f(i)=i=km(1)ik(ik)(mk)×(mk1)n1

那么 g(0) 就是答案啦

SDOI2016 排列计数

考虑设 f(x) 为钦定 x 个位置必须放对,剩下的随便放,那么 f(x)=(nx)(nx)!=n!x!

乘上 (nx) 的原因是我们要先选出来这 x 个位置。然后 g(x) 表示恰好放对 x 个位置的方案数,我们有

f(x)=i=xn(ix)g(i)g(x)=i=xn(ix)(1)ixf(i)

然后你用 f(x)=n!x! 化简一下发现

g(x)=i=xni!x!(ix)!(1)ix×n!i!=i=xnn!x!(nx)!×(1)ix(nx)!(ix)!=(nx)(nx)!i=0nx(1)ii!

前后都可以 O(n) 预处理,于是这题就做完了。AC Code

BZOJ2839 集合计数

先选出 x 个元素必须在交集里面,那么剩下的 nx 个元素可以构成 2nx 个集合,可以随便选但不能一个都不选,因此方案数为

f(x)=(nx)(22nx1)

然后设 g(x) 为交集大小恰好为 k 的方案数,那么

f(x)=i=xn(ix)g(i)g(x)=i=xn(1)ix(ix)f(i)

注意到只有一次询问,因此可以先算出来 f 然后直接算出来 g。不难在 O(N) 时间内解决。AC Code

BZOJ3622 已经没有什么好害怕的了

记糖果为 A1n,药片为 B1n。那么当 n,k 不同奇偶时无解,否则应当有 n+k2 个位置满足 Ai>Bi,剩下的为 Ai<Bi

下面记 k 为原来的 n+k2。 仍然是钦定 k 个位置,让这 k 个位置满足 Ai>Bi,想想怎么算方案数。发现不是很好用组合数算。

对于每个 Ai 我们算出来 Ci 表示 B<Ai 的元素个数,将 A 从小到大排序,那么 C 序列递增且前面的 C 是后面的子集。

现在相当于要钦定 k 个位置选出 Ci 所代表的集合中的数且不能重复,剩下的随便选。

这个可以 DP 做,f(i,j) 表示前 i 个数配了 j 组时的方案数,那么 f(i,j)=f(i1,j)+f(i1,j1)×(Cj(j1))

那么记 Fj=(nj)!f(n,j),答案就是 F 做一个二项式反演。于是这题就做完了,时间复杂度 O(n2)AC Code

JSOI2011 分特产

f(k) 为钦定 k 个人,他们分不到特产,剩下的人随便分,的方案数。那么答案就是 f 做一个二项式反演。

注意到 f(k) 实际上等价于给 nk 个人分特产,不过可以有人没分到的方案数。

然后我们发现其实每种特产大概是独立的,那么给 m 个人分的时候答案就是

i=1n(ai+m1m1)

我们对每个 m 把这东西算一遍就得到了 f,再反演就得到了 g。暴力算是 O(n2) 的,已经可以通过。AC Code

实际上我们拆拆式子发现

i=1n(ai+m1m1)=i=1n(ai+m1)!ai!(m1)!=i=1n(ai+m2)!ai!i=1n(ai+m1)×1((m1)!)n

我们发现只要能快速算出来 (ai+m1) 就能递推。

F(x)=(ai+x),那么可以分治 NTT 在 O(nlog2n) 的时间内得到 F,再 O(nlog2n) 做个多点求值,就得到了 O(nlog2n) 的算法。

NOI Online#2 提高组 游戏

和 BZOJ3622 比较相似,考虑钦定 k 个位置,让这 k 个位置不是平局。我们将 A 的点染黑,B 的点染白。

现在相当于要选出 k 组互为祖孙关系的点对,求方案数。

这个可以用树形 DP 做,设 f(u,j) 为只考虑点 u 子树内的点,配 j 对的方案。

Xuu 子树中白点个数,Yuu 子树中黑点个数,转移时考虑看 u 是否配对:

  • 如果 u 不配对,那么直接把 u 的儿子的背包合并上来即可。
  • 如果 u 配对,不妨设 u 是黑点,此时相当于子树中已经配了 j1 对,那么 u 还有 Xu(j1) 种选择。因此将子树内 j1 的背包合并上来再乘 (Xu(j1)) 即可。

那么我们可以 O(n2) 算出来钦定 k 个位置的方案数,再 O(n2) 反演一遍就完事了。AC Code

JSOI2015 染色问题

我们发现这题有三个限制。如果没有限制,那么答案就是 (C+1)n×m

考虑设 f(i,j,k) 为钦定某 i 行,某 j 列全都空着,某 k 种颜色不选的方案数,那么 f(i,j,k)=(Ck+1)(ni)×(mj)(ni)(mj)(Ck)

然后设 g(i,j,k) 为恰好 ijk 种颜色不选的方案数,有

f(i,j,k)=x=iny=jmz=kC(xi)(yj)(zk)g(i,j,k)

发现是个三维的二项式反演,我们猜想

g(i,j,k)=x=iny=jmz=kC(1)x+y+zijk(xi)(yj)(zk)f(i,j,k)

从容斥的角度考虑一下,感觉很对。直接做要带个 log,不过不难做到 O(n3)AC Code

注意到其实三维中有一维可以直接算出来,所以不难优化到 O(n2)。。。(我是傻子qaq

ABC266G Yet Another RGB Sequence

考虑钦定 i 个位置是 RG,那么还剩 RiRGiGBB,方案数可以随便算。

于是就做完了,果然是板子题。

ABC217G Groups

我们考虑对非空这个条件做容斥。

具体来说把 1,2,N 分成 M 组,第 i 组中每个数都 modM=i,设其大小为 Ci

现在我们钦定其中某 i 组是空的,那么

f(i)=j=0M1(kiCj)×Cj!

那么答案可以直接通过二项式反演 O(M) 得到。

我们发现如果直接算的话需要算 N 次,每次都要 O(NM),过不去。

但是可以发现本质不同的 ki 其实只有 O(N) 组,因此直接处理出来所有的

Fx=j=0M1(xCj)×Cj!

然后算 f(i) 就只需要查表了。总的复杂度为 O(NM)AC Code

CF285E Positions in Permutation

f(i,j,0/1,0/1) 表示由 1i 构成的排列,有 j 个 good position 的方案数,后面两个 0/1 的含义待会再说。

我们考虑这样由 1,2,,i 的排列构建一个 1,2,,i+1 的排列:先把最后一位放上 i+1,再将最后一位和前面的某一位 swap 一下。

这样一来,我们只需要分别计算出来有多少种 swap 可以使得 good position 的数量 +1/1/ 不变即可。

我们考虑 x 满足 ax=i 以及 ai 的值是什么。进行一个分类:

  • 如果 i+1 和某个 x,i 之外的数 swap 了, 那么如果原本那个位置是 good position,j 需要减一;否则不变。
  • 如果和 x 进行 swap,那么 i+1 会是一个 good position,但是 x 那个位置原本是不是 good position 我们不知道,因此需要记录一下。
  • 如果和 i 进行 swap,那么 i 会是一个 good position,但是这个位置原本是不是 good position 我们也不知道,需要记录一下。

因此状态就是:

  • f(i,j,0/1,0/1) 表示由 1i 构成的排列,有 j 个 good position,第 i 个位置是不是 i1,第 i1 个位置是不是 i,的方案数。

转移分类讨论一下就行了。等等说好的二项式反演在哪里呢

我们思考一下容斥做法:直接钦定某 k 个位置为 good position,剩下的位置的方案数我们默认为 1

我们发现这个东西类似于一个匹配:

我们把黑边拉直,然后相当于要从 n1 条边中选出 k 条互不相邻的边。简单插板得到 f(k)=(nkk)

那么我们的 F 就是 f 和自己卷一下,答案就是

G(m)=i=mn(1)imF(k)

暴力 O(n2) 计算已经可以通过本题。注意到 F 是个卷积,因此可以做到 O(nlogn)

CF997C Sky Full of Stars

相信做了之前那么多题之后这题已经非常简单了。。。

考虑钦定某 k 列是同一种颜色,剩下的随便填,并且需要满足每一行都不是同一种颜色。有

f(k)={(3n3)n,k=0(nk)×(3×(3nk1)n+(3k3)×3n(nk)),k>0

然后二项式反演再做个小容斥就完事了。时间复杂度 O(nlogn)O(n)AC Code

CF995F Cowmpany Cowmpensation

这题有个拉格朗日插值的做法,不过我们可以用容斥过掉它。

我们发现虽然值域很大,但是实际上用到的数只可能有 O(n) 种。

g(i) 为恰好用 [1,i] 中每个数填好,并且每种数至少出现一次,的方案数,那么答案就是 x(Dx)g(x)

这是因为我们可以把一种方案离散化掉,那么离散化到 [1,x] 的方案数恰为 (Dx)

我们发现至少出现一次看着就很容斥,因此可以求出来 f(i) 表示只用 [1,i] 中的数,随便填(可以有某些数没有用到)的方案数。

那么 g 其实就是 f 二项式反演一下,于是就可以 O(n2) 直接算了。代码懒得写了,,先坑着

posted @   云浅知处  阅读(272)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
点击右上角即可分享
微信分享提示