「学习笔记」二项式反演、斯特林数、Min-max 容斥
点击查看目录
Something:
题单里的部分题目还没有写所以本文在例题方面没有施工完毕,发出来仅仅是因为这篇博太常需要翻阅但是又被积压在草稿箱底部 .
补完后会删除这段话 .
格路计数
一个比较经典的 trick .
在一个 n×m 的方格内,只能向上或向右走,求从 (0,0) 走到 (n,m) 的方案数 .
答案是 (n+mn),组合意义是 n+m 次移动中选出 n 次向上移动 .
另一种解决方式是简单 DP,fi,j=fi−1,j+fi,j−1 .
在求解类似 ∑ni=1∑mj=1(ai+aj+bi+bjai+bi) 的问题时,如果 nm 较大但值域较小,可以考虑转化为格路计数,在所有 (−ai,−bi) 处初始化,使用 DP 算出所有 (aj,bj) 的值 .
板子是 AGC001E .
二项式反演
终于能填这个坑了啊 .
大量参考:link1, link2 .
形式一与形式二是更常用的形式 .
形式零
假设全集 U=A1,A2,⋯,An 的任意 i 个元素并集、交集都相等,设 f(n) 表示任意 i 个集合的补集的交集,g(n) 表示任意 i 个集合的交集 .
特别的,f(0)=|U|,g(0)=|U| .
记 A 补集为 Ac,有一条容斥等式:
|A1∩A2∩⋯∩An|=|U|−n∑i=1∣∣Aci∣∣+n∑i=1n∑j=1∣∣Aci∩Acj∣∣−⋯+(−1)n∣∣Ac1∩Ac2∩⋯∩Acn∣∣
左边就是 g(n),右边相当于 ∑ni=0(ni)f(i) . 即 g(n)=∑ni=0(−1)i(ni)f(i) .
补集的补集就是原集,那么同理可得 f(n)=∑ni=0(−1)i(ni)g(i) .
那么可以得到形式零:
f(n)=n∑i=0(−1)i(ni)g(i)⇔g(n)=n∑i=0(−1)i(ni)f(i)
其他形式都可以在这个形式基础上变形得出 .
形式一
f(n)=n∑i=0(ni)g(i)⇔g(n)=n∑i=0(−1)n−i(ni)f(i)
有一个组合意义:f(i) 为在一个集合中钦定 i 个元素被选择,其他元素随便选的方案数,g(i) 为在该集合中选出恰好 i 个元素的方案数 .
两个代数证明:
证明 1
令 h(n)=(−1)ng(n),带入形式零:
f(n)=n∑i=0(ni)h(i)⇔h(n)(−1)n=n∑i=0(−1)i(ni)f(i)
观察发现 (−1)n+i=(−1)n−i,因此得出形式二:
f(n)=n∑i=0(ni)h(i)⇔h(n)=n∑i=0(−1)n−i(ni)f(i)
□
证明 2
硬带:
f(n)=n∑i=0(ni)g(i)=n∑i=0(ni)i∑j=0(−1)i−j(ij)f(j)=n∑i=0i∑j=0(ni)(ij)(−1)i−jf(j)=n∑j=0f(j)n∑i=j(ni)(ij)(−1)i−j=n∑j=0f(j)n∑i=j(nj)(n−ii−j)(−1)i−j=n∑j=0(nj)f(j)n−j∑k=0(n−ik)1n−j−k(−1)k
∑n−jk=0(n−ik)1n−j−k(−1)k 这一坨,当 n=j 时等于 1,否则等于 (1−1)n−j=0 .
带回:
f(n)=n∑j=0(nj)f(j)n−j∑k=0(n−ik)1n−j−k(−1)k=n∑j=0(nj)f(j)[n=j]=(nn)f(n)=f(n)
□
形式二
f(n)=m∑i=n(−1)i(in)g(i)⇔g(n)=m∑i=n(−1)i(in)f(i)
证明考虑直接代入:
f(n)=m∑i=n(−1)i(in)g(i)=m∑i=n(−1)i(in)m∑j=i(−1)j(ji)f(j)=m∑j=nf(j)j∑i=n(in)(ji)(−1)i+j=m∑j=nf(j)j∑i=n(jn)(j−ni−n)(−1)2j+(i−j)=m∑j=i(jn)f(j)j−n∑k=0(j−nk)(−1)k=m∑j=n(jn)f(j)[j=n]=(nn)f(n)=f(n)
□
形式三
f(n)=m∑i=n(in)g(i)⇔g(n)=m∑i=n(−1)i−n(in)f(i)
证明与形式一比较类似:
f(n)=m∑i=n(in)g(i)=m∑i=n(in)m∑j=i(−1)j−i(ji)f(j)=m∑j=nf(j)j∑i=n(ji)(in)(−1)j−i=m∑j=n(jn)f(j)j∑i=n(j−nj−i)(−1)j−i=m∑j=n(jn)f(j)j−n∑k=0(j−nk)1j−n−k(−1)k=m∑j=n(jn)f(j)[n=j]=(nn)f(n)=f(n)
□
斯特林数
第一类斯特林数
定义
「第一类斯特林数(斯特林轮换数)」记作 [nk] 或 s(n,k),表示将两两不同的 n 个元素划分为 k 个互不区分的轮换的方案数 .
「轮换」指的是一个首尾相接的序列,例如说 [A,B,C,D]=[B,C,D,A]=[C,D,A,B]=[D,A,B,C],但是 [A,B,C,D]≠[D,C,B,A] .
递推式
[nk]=[n−1k−1]+(n−1)[n−1k]
特别的,[n0]=[n=0] .
比较好考虑组合意义,一种情况是新开一个轮换,另一种是选一个轮换插入 . 注意插入位置不同形成的轮换不同,共有 n−1 个位置可以插入 .
似乎没有实用的通项公式 .
第二类斯特林数
定义
「第二类斯特林数(斯特林子集数)」记作 {nk} 或 S(n,k),表示将两两不同的 n 个元素划分为 k 个互不区分的子集的方案数 .
递推式
{nk}={n−1k−1}+k{n−1k}
特别的,{n0}=[n=0] .
组合意义两种情况和第一类斯特林数一样,但是子集不区分顺序,因此第二种情况共有 k 种插入方式 .
通项公式
{nk}=k∑i=0(−1)k−iini!(k−i)!
证明考虑容斥:F(i) 表示将两两不同的 n 个元素划分为 i 个互相区分的集合(不允许空集)的方案数,G(i) 表示将两两不同的 n 个元素划分为 i 个互相区分的集合(允许空集)的方案数 .
显然有:
G(i)=in=i∑j=0(ij)F(j)
第二种表达方式是枚举非空集个数 .
使用二项式反演:
F(i)=i∑j=0(−1)i−j(ij)G(j)=i∑j=0(−1)i−j(ij)jn=i∑j=0i!(−1)i−jjnj!(i−j)!
把 F(k) 划分出的集合的顺序去掉即可得到 {nk}:
{nk}=F(k)k!=i∑j=0(−1)i−jjnj!(i−j)!
应用:普通幂、下降幂与上升幂互相转化
一个很奇怪的事情是网上的证明很少,于是我贺了具体数学 .
记上升阶乘幂 x¯¯¯n=∏n−1k=0(x+k),下降阶乘幂 xn––=∏n−1k=0(x−k) .
首先有公式「普通幂转下降幂」:
xn=∑k{nk}xk––
考虑使用数学归纳法证明 . 我们由 xk+1–––––=xk––(x−k) 可推出 x⋅xk––=xk+1–––––+kxk,那么:
x⋅xn−1=x∑k{n−1k}xk––=∑k{n−1k}xk+1–––––+∑k{n−1k}kxk––=∑k{n−1k−1}xk––+∑k{n−1k}kxk––=∑k(k{n−1k}+{n−1k−1})xk––=∑k{nk}xk––
使用类似的方法即可获得公式「上升幂转普通幂」:
x¯¯¯n=∑k[nk]xk
接下来考虑如何倒过来转化,即「普通幂转上升幂」和「下降幂转普通幂」 .
观察发现,如果我们找到了上升幂与下降幂之间的关系,带入「普通幂转下降幂」的式子就可以获得「普通幂转上升幂」,另一个同理 .
这个关系并不难找:
xn––=(−1)n(−x)¯¯¯n
然后对「普通幂转下降幂」进行变形再代入:
(−x)n=∑k{nk}(−x)k––(−1)nxn=∑k{nk}(−1)k(−x)¯¯¯k
得到「普通幂转上升幂」:
xn=∑k{nk}(−1)n−kx¯¯¯k
同理得到「下降幂转普通幂」:
xn––=∑k[nk](−1)n−kxk
其实这是符合斯特林反演的,所以你会斯特林反演的话也能得出后面两个式子 .
我懒得证了 . 挂个链接 .
Min-max 容斥
若 S⊆T,则不难发现有 |S∪T|=max{|S|,|T|},|S∩T|=min{|S|,|T|} .
利用这一性质即可利用容斥公式,通过集合内的一个最值求出另一最值:
minx∈Sx=∑T⊆S,T≠∅(−1)|T|−1maxx∈Txmaxx∈Sx=∑T⊆S,T≠∅(−1)|T|−1minx∈Tx
看起来挺没用的 .
比较强的是根据期望线性性有下面这条式子:
E(minx∈Sx)=∑T⊆S,T≠∅(−1)|T|−1E(maxx∈Tx)E(maxx∈Sx)=∑T⊆S,T≠∅(−1)|T|−1E(minx∈Tx)
这个相当有用,因为有时候一个最值的期望远没有另一种好求 .
另外还可以扩展到 gcd 和 lcm:
lcmx∈Sx=∏T⊆S,T≠∅(gcdx∈Tx)(−1)|T|−1
虽然我很没用,但看到几位这么有用,真好!
例题
积木
n 堆积木,每堆有 ai 个蓝色积木,bi 个绿色积木,ci 个红色积木 . 每次任选两堆积木,用完这两堆之间的所有积木 建出一栋楼,求总方案数 .
两个方案不同,当且仅当选取的积木堆不同或建成高楼的某一层颜色不同 .
1≤n≤2×105,0≤ai,bi,ci≤150 .
固定两堆积木,方案数为 (ai+aj+bi+bj+ci+cjai+aj,bi+bj,ci+cj) .
发现是一个三维格路计数的形式,值域不大故使用 DP 求解 .
对 a 和 b 进行排序,使得处理大小时可以直接从前缀和后缀转移过来 .
设 Fi,j 表示前 i 个 ai 中,有多少种方案钦定配对了 j 个满足 a>b 的二元组,有转移:
Fi,j=Fi−1,j+(pi−(j−1))Fi−1,j−1
其中 pi 满足 bpi<ai<bpi+1 .
对于状态中没有进行配对的,令它们肆意配队,为了更方便形式化 f(i)=(n−i)!Fn,i 表示整个序列钦定 j 个满足 a>b 的二元组的方案数 .
设 g(n) 表示序列中存在恰好 j 个满足 a>b 的二元组的方案数,二项式反演:
f(k)=n∑i=k(ik)g(i)⇔g(k)=n∑i=k(−1)i−k(ik)f(i)
答案即为 g(n+k2) .
看到这个「恰好」就比较套路的放上二项式反演:设 f(k) 表示恰好 k 个人被碾压,g(x) 表示钦定 k 个人被碾压 .
不难得到反演式子:
g(k)=n∑i=k(ik)f(i)⇔f(k)=n∑i=k(−1)i−k(ik)g(i)
考虑求 g(k),有式子:
g(k)=(n−1k)m∏i=1Ui∑s=1(n−k−1Ri−1)sn−Ri(Ui−s)Ri−1
简单解释:选出 k 个人被钦定,对于每一科考虑枚举 D 神的分数,在没被钦定的 n−k−1 个人中选出 Ri−1 个人作为分数比 D 神高的人,然后可以知道每个人分数的可能数,其积为每个人的分数的总可能数 .
这样复杂度是基于值域的,考虑展开后面的依托:
Ui∑s=1(n−k−1Ri−1)sn−Ri(Ui−s)Ri−1=Ui∑s=1(n−k−1Ri−1)sn−RiRi−1∑j=0(Ri−1j)Uji(−1)Ri−1−jsRi−1−j=(n−k−1Ri−1)Ri−1∑j=0(−1)Ri−1−j(Ri−1j)UjiUi∑s=1sn−j−1=(n−k−1Ri−1)h(i)
这个 h(i) 部分只与 i 有关所以单独提出来进行预处理,现在和值域有关的部分只剩下了后面的自然数幂和,这样就可以拉插或伯努利数处理了 .
但是我不会拉插也不会伯努利数,咋整呀?
答案是用扰动法可以得到自然数幂和的一个递推式:
St(n)=n∑k=1kt=(n+1)t+1−∑t−1j=0(t+1j)Sj(n)(t+1)
我写这个是为了让你知道我代码里有啥,最好还是用拉插的,不然别人也不知道你在干什么 .
这样可以 O(mR2)=O(n3) 预处理出所有的 h(i),然后把它带回原式:
f(k)=n∑i=k(−1)i−k(ik)(n−1i)m∏j=1(n−i−1Rj−1)h(j)
可以 O(n2) 算出 .
第 x 段贡献是:
mx−ax∑i=1ik−m∑i=x(ai−ax)k
后一半暴力算,前一半是个经典的自然数幂和 .
当然可以插出来不过放在斯特林数还是要尊重一下:
n∑i=1ik=n∑i=1k∑j=1{kj}ij–=n∑i=1k∑j=1{kj}(ij)j!=k∑j=1{kj}j!n∑i=1(ij)=k∑j=1{kj}j!(n+1j+1)=k∑j=1{kj}j!(n+1)j+1––––(j+1)!
斯特林数直接 O(k2) 预处理,后面下降幂由于 j 不大直接暴力计算 .
考虑使用斯特林数将普通幂转化为下降幂,进一步转为组合数 .
S(u)=n∑v=1k∑i=0{ki}dis(u,v)k––=n∑v=1k∑i=0{ki}(dis(u,v)i)i!=k∑i=0{ki}i!n∑v=1(dis(u,v)i)
设 fu,i=∑v∈u's subtree(dis(u,v)i),有转移:
fu,i=∑v∈u's son∑x∈v's subtree(dis(v,x)+1i)=∑v∈u's son∑x∈v's subtree(dis(v,x)i)+(dis(v,x)i−1)=∑v∈u's sonfv,i+fv,i−1
然后换个根就做完了 .
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步