zoukankan      html  css  js  c++  java
  • 组合计数和反演

    组合计数和反演

    包含内容

    二项式反演、斯特林反演、莫比乌斯反演、第一类斯特林数、第二类斯特林数。

    反演

    首先我们有两个数列({f_i})和数列({g_i}),他们之间满足

    [g_n=sum_{i=0}^n a[n][i]f_i ]

    这里我们可以通过({f_i})的值推出({g_i})
    那么反演过程就是找到一个数组(b),使得能够用({g_i})的值,反推出({f_i})的值。
    也就是

    [f_n=sum_{i=0}^n b[n][i]g_i ]

    如果只通过上面两个式子来考虑的话,事实上这就是一个反解线性方程组的过程,然而实际上整个方程组已经是一个下三角的形式了,因此我们可以考虑更加快捷的方式来进行计算。

    这里给出克罗内克函数

    [delta(i,j)=egin{cases}1&i=j\0&i eq jend{cases} ]

    只是为了后面的书写的方便而介绍这个函数。

    考虑反演的过程

    [f_n=sum_{i=0}^n b[n][i]g_i ]

    我们把(g_i)的计算式直接带入当前式子,那么就会得到:

    [egin{aligned}f_n=sum_{i=0}^n b[n][i]g_i&=sum_{i=0}^n b[n][i]sum_{j=0}^ia[i][j]f_j\&=sum_{i=0}^n f_isum_{j=i}^nb[n][j]*a[j][i]end{aligned} ]

    考虑每一个(f_i)前面的系数,显然只有(f_n)的系数为(1)
    因此(a,b)之间的关系可以简单的写成。

    [sum_{j=i}^nb[n][j]*a[j][i]=delta(n,i) ]

    同理,把(f)带入到(g)的求和式中,可以推出

    [sum_{j=i}^na[n][j]*b[j][i]=delta(n,i) ]

    如果满足这两个式子的话,那么意味着反演也是成立的。
    然而这样子很虚幻,因为看起来也不知道有什么用,那么接下来就带入具体的东西来写QwQ。

    二项式反演

    这个玩意似乎经常在容斥里面用到,或者说本质上就是一个容斥。
    它的式子可以写成这个样子:

    [egin{aligned}f_n&=sum_{i=0}^n(-1)^i{n choose i}g_i\g_n&=sum_{i=0}^n(-1)^i{nchoose i}f_iend{aligned} ]

    正反看起来是一模一样的。
    或者说写成更加常见的一种形式

    [egin{aligned}f_n&=sum_{i=0}^n{nchoose i}g_i\g_n&=sum_{i=0}^n(-1)^{n-i}{nchoose i}f_iend{aligned} ]

    证明的话直接类似前面把(f_i)带入(g_n)的求和式之中,通过组合数的化简即可简单的证明。

    [egin{aligned}g_n&=sum_{i=0}^n(-1)^{n-i}{nchoose i}f_i\&=sum_{i=0}^n(-1)^{n-i}{nchoose i}sum_{j=0}^i{ichoose j} g_j\&=sum_{j=0}^n g_isum_{i=j}^n{nchoose i}{ichoose j}(-1)^{n-i}\&=sum_{j=0}^n g_jsum_{i=j}^n{nchoose j}{n-jchoose i-j}(-1)^{n-i}\&=sum_{j=0}^n g_j({nchoose j}sum_{i=j}^n{n-jchoose i-j}(-1)^{n-i})\&=sum_{j=0}^n g_j({nchoose j}sum_{i=0}^{n-j}{n-jchoose i}(-1)^{n-j-i})\&=sum_{j=0}^n g_j({nchoose j}(1-1)^{n-j})\&=g_nend{aligned} ]

    当然,还可以写成这个样子:

    [egin{aligned} f_k&=sum_{i=k}^n{ichoose k}g_i\ g_k&=sum_{i=k}^n{ichoose k}f_i(-1)^{i-k} end{aligned} ]

    证明同理。

    应用

    • 错排问题

    求完全错位的排列方案数,即不存在(p_i=i)的排列({p})的个数。

    这个是有递推做法的,但是因为这里在写二项式反演,所以不考虑其他的做法。
    (f_i)表示恰好有(i)个位置时满足不存在(p_k=k)的方案数,也就是答案。
    那么我们推出一个式子:

    [n!=sum_{i=0}^n{nchoose i}f_i ]

    即枚举哪些位置满足(p_k=k),剩下位置强制满足错排关系,这样子就能够不重不漏的计算出(n!)个排列。
    这样一来令(g_n=n!),有二项式反演的式子:

    [f_n=sum_{i=0}^n(-1)^{n-i}{nchoose i}g_i=n!sum_{i=0}^nfrac{(-1)^i}{i!} ]

    • 染色问题

    (1 imes n)的一排格子,有(m)种颜色,每个格子染一个颜色,相邻格子颜色不能相同,每种颜色都至少被用到(1)次,求染色方案数。

    如果不考虑每个颜色都要被用一次的话,答案显然就是(m*(m-1)^{n-1}),这样也就是至多用了(m)种颜色。
    (f_i)表示恰好用了(i)种颜色的方案数,那么与之对应的设(g_i)表示至多用了(i)种颜色的方案数。
    那么我们推出一个转移:

    [g_m=m*(m-1)^{n-1}=sum_{i=0}^n {nchoose i}f_i ]

    二项式反演得到:

    [f_m=sum_{i=0}^m(-1)^{m-i}{mchoose i}g_i ]

    其他还有些题目之类的东西懒得写了QwQ。

    第一类斯特林数

    递推式

    (egin{bmatrix}n\mend{bmatrix})表示(n)个元素分成(m)个环的方案数。
    那么递推式很显然:

    [egin{bmatrix}n\mend{bmatrix}=egin{bmatrix}n-1\m-1end{bmatrix}+(n-1)*egin{bmatrix}n-1\mend{bmatrix} ]

    即考虑先前已经放好的(n-1)个数,当前新加入的这个元素有两种选择,第一种是自己成一个环,贡献是(egin{bmatrix}n-1\m-1end{bmatrix});第二种是放到环内,那么它可以放在任意一个数的前面,所以就是((n-1)*egin{bmatrix}n-1\mend{bmatrix})
    为了好写,接下来可能就偷懒写成(S_1(n,m))了。

    一点小性质

    • (displaystyle n!=sum_{i=0}^n S_1(n,i))
      证明?第一类斯特林数的本质是环排列的个数,环的本质可以理解为置换。那么显然所有第一类斯特林数对应的环排列可以和置换一一对应,所以总数就是(n!)
    • (displaystyle x^{underline{n}}=sum_{i=0}^nS_1(n,i)(-1)^{n-i}x^i),其中(x^{underline n})表示(n)次下降幂
      证明可以用数学归纳法来解决。

    [egin{aligned}x^{underline{n+1}}&=(x-n)x^{underline n}\ &=(x-n)*sum_{i=0}^negin{bmatrix}n\iend{bmatrix}(-1)^{n-i}x^i\ &=sum_{i=1}^{n+1}egin{bmatrix}n\i-1end{bmatrix}(-1)^{n-i-1}x^{i}-nsum_{i=1}^{n+1}egin{bmatrix}n\iend{bmatrix}(-1)^{n-i}x^{i-1}\ &=sum_{i=0}^{n+1}egin{bmatrix}n\i-1end{bmatrix}(-1)^{n-i-1}x^i+nsum_{i=0}^{n+1}egin{bmatrix}n\iend{bmatrix}(-1)^{n-i+1}x^i\ &=sum_{i=0}^{n+1}(egin{bmatrix}n\i-1end{bmatrix}+n*egin{bmatrix}n\iend{bmatrix})(-1)^{n+1-i}x^i\ &=sum_{i=0}^{n+1}egin{bmatrix}n+1\iend{bmatrix}(-1)^{n+1-i}x^i end{aligned}]

    • (displaystyle x^{overline n}=sum_{i=0}^n S_1(n,i)x^i),其中(x^{overline n})表示(x)(n)次上升幂
      可以类似上面的东西证明

    这几个式子还是很有用的,揭示了第一类斯特林数和下降幂之间的关系,而下降幂很明显可以写成排列的形式,也说明了第一类斯特林数和组合计数之间有着紧密的联系。

    预处理

    第一类斯特林数的生成函数可以写成:

    [sum_{i=0}^n S_1(n,i)x^i=prod_{i=0}^{n-1}(x+i) ]

    得到的方法很简单,把(n)为定值时的所有的第一类斯特林数按照(n)分类分成行,发现每次的(S_1(n,m))转移必定要从(n-1)行转移过来,而每次转移都是(m-1)变到(m),系数为(1),因此有一项(x),同理有一项(n-1),因此就可以得到上面的那个生成函数。

    考虑如何预处理整行第一类斯特林数,用上述式子可以直接分治+(FFT)做到(O(nlog^2n))
    实际上有一种只需要一个(log)的倍增方法。(问了lun终于懂了)
    (displaystyle F_n(x)=prod_{i=0}^{n-1}(x+i)),则有(F_{2n}(x)=F_n(x)F_{n}(x+n))
    (F_n(x))我们递归求得其答案,现在考虑如何利用(F_n(x))快速求出(F_n(x+n))
    在这里我们假设(displaystyle F_n(x)=sum_{i=0}^{n-1} a_i x^i)

    [egin{aligned} F_n(x+n)&=sum_{i=0}^{n-1}a_i (x+n)^i\ &=sum_{i=0}^{n-1}a_isum_{j=0}^i{ichoose j}n^{i-j}x^j\ &=sum_{i=0}^{n-1}(sum_{j=i}^n {jchoose i}n^{j-i}a_j)x^i end{aligned}]

    括号内的部分拆开之后,可以分成差相等的两个部分,意味着可以翻转之后卷积。
    那么每次递归前一半,后面一半卷积求解即可得到答案。
    时间复杂度为一个(log)

    第二类斯特林数

    这个其实原来我写过一次啦QwQ。
    (egin{Bmatrix}n\mend{Bmatrix})表示将(n)个元素放入(m)个相同盒子里,每个盒子非空的方案数。
    递推式和上面类似

    [egin{Bmatrix}n\mend{Bmatrix}=egin{Bmatrix}n-1\m-1end{Bmatrix}+m*egin{Bmatrix}n-1\mend{Bmatrix} ]

    考虑最后放入的元素是新建一个盒子还是放入一个原有的盒子即可。
    后面偷懒写成(S_2(n,m))的形式。
    上述式子是直接递推,事实上第二类斯特林数有容斥计算的方法。

    [S_2(n,m)=frac{1}{m!}sum_{i=0}^m(-1)^i{mchoose i}(m-i)^n ]

    即先将盒子编号,最后结果出去顺序即可。考虑有几个盒子为空,枚举出来,然后剩下的元素随便放在非空的盒子里,因为这里算完之后是至少(i)个盒子为空,所以需要容斥。
    这个式子拆开组合数之后可以写成卷积的形式,意味着我们可以在一个(log)的复杂度里求解(S(n,i),iin[0,n])

    这里和自然数幂之间有一个式子

    [m^n=sum_{i=0}^mS_2(n,i){mchoose i}i! ]

    (m^n)理解为把(n)个球任意放到(m)个有区别的盒子中,那么我们枚举哪些盒子非空,然后放进去的方案数就是第二类斯特林数乘阶乘。
    当然,事实上上面的这个式子也可以写成上升幂和下降幂的形式

    [egin{aligned}m^n&=sum_{i=0}^mS_2(n,i){mchoose i}i!\&=sum_{i=0}^mS_2(n,i)frac{m!}{(m-i)!}\&=sum_{i=0}^mS_2(n,i)m^{underline i}end{aligned} ]

    upd:补充一个自然数幂和的式子:

    [egin{aligned} S(n)&=sum_{i=1}^n i^k\ &=sum_{i=1}^nsum_{j=0}^k egin{Bmatrix}k\jend{Bmatrix}i^{underline j}\ &=sum_{j=0}^kegin{Bmatrix}k\jend{Bmatrix}sum_{i=1}^ni^{underline j}\ &=sum_{j=0}^kegin{Bmatrix}k\jend{Bmatrix}j!sum_{i=1}^n{ichoose j}\ &=sum_{j=0}^kegin{Bmatrix}k\jend{Bmatrix}j!{n+1choose j+1}\ &=sum_{j=0}^kegin{Bmatrix}k\jend{Bmatrix}frac{(n+1)^{underline {j+1}}}{j+1} end{aligned}]

    中间有一步(displaystyle sum_{i=1}^n{ichoose j}={n+1choose j+1}),这个的证明可以理解为从(n+1)个位置中选择(j+1)个位置,先确定最靠左的那个求的位置,我们枚举其位置,这样子剩下的位置就是(n+1-i)个,从中选出(j)个,就是上述式子了。
    这样子用第二类斯特林数计算自然数幂和就不需要考虑求逆的问题了。

    斯特林反演

    直接摆式子吧

    [egin{aligned} f(n)&=sum_{i=1}^n egin{Bmatrix}n\iend{Bmatrix}g(i)\ g(n)&=sum_{i=0}^n(-1)^{n-i}egin{bmatrix}n\iend{bmatrix}f(i)end{aligned} ]

    为了证明这个东西我们接下来可以补一堆式子啦。
    首先这个东西叫做反转公式

    [egin{cases}sum_{k=m}^n(-1)^{n-k}egin{bmatrix}n\kend{bmatrix}egin{Bmatrix}k\mend{Bmatrix}=delta(n,m)\sum_{k=m}^n(-1)^{n-k}egin{bmatrix}k\mend{bmatrix}egin{Bmatrix}n\kend{Bmatrix}=delta(n,m)end{cases} ]

    仔细想想,这不就是上面反演如果成立的话需要满足的两个式子吗?
    所以只需要证明反转公式成立,那么类似前面的带入方法,就可以证明斯特林反演。
    我们先考虑几个很显然的式子就可以很方便的帮忙证明反转公式了。

    • (x^{underline n}=(-1)^n (-x)^{overline n})

    • (x^{overline n}=(-1)^n (-x)^{underline n})

    这两个式子很显然,就不证明了。
    接下来我们就可以来推式子了。

    [egin{aligned} n^m&=sum_{i=0}^megin{Bmatrix}m\iend{Bmatrix}n^{underline i}\ &=sum_{i=0}^megin{Bmatrix}m\iend{Bmatrix}(-1)^i(-n)^{overline i}\ &=sum_{i=0}^megin{Bmatrix}m\iend{Bmatrix}(-1)^isum_{j=0}^i egin{bmatrix}i\jend{bmatrix}(-n)^j\ &=sum_{j=0}^m (-n)^jsum_{i=j}^megin{Bmatrix}m\iend{Bmatrix}egin{bmatrix}i\jend{bmatrix}(-1)^i\ &=sum_{j=0}^m n^jsum_{i=j}^megin{Bmatrix}m\iend{Bmatrix}egin{bmatrix}i\jend{bmatrix}(-1)^{i+j} end{aligned}]

    显然当且仅当(j=m)时后面那堆式子才为(1)
    那么就证明了反转公式的一半,另外一半显然可以同理证明。
    这样一来斯特林反演就证明完了。

    莫比乌斯反演

    可以说是我们最熟悉的反演了。主要用于和约数相关的关系。

    [egin{aligned} g(n)&=sum_{d|n}f(d)\ f(n)&=sum_{d|n}g(d)mu(frac{n}{d}) end{aligned} ]

    证明,直接带进去来爆算:

    [egin{aligned} g(n)&=sum_{d|n}f(d)\ &=sum_{d|n}sum_{dd|d}g(dd)mu(frac{d}{dd})\ &=sum_{dd|n}g(dd)sum_{d|n,dd|d}mu(frac{d}{dd})\ &=sum_{dd|n}g(dd)sum_{d|(n/dd)}mu(d)\ &=sum_{dd|n}g(dd)delta(n,dd)\ &=g(n) end{aligned} ]

    这里利用了(sum_{d|n}mu(d)=delta(n,1))
    还有另外一种形式,和二项式反演的另外一种形式很类似。

    [egin{aligned}g(n)&=sum_{n|d}f(d)\f(n)&=sum_{n|d}g(d)mu(frac{d}{n})end{aligned} ]

    证明方法类似。

    题目

    单独分开一篇总结QwQ

  • 相关阅读:
    word中怎么插入各种水平分隔线?
    Shell脚本--磁盘空间有超过80%时发信息
    Linux、Ubuntu 系统安装 MYSQL-python 失败解决方案
    安卓 okhttp 拦截重复请求
    安卓 drawable xml 实现多边框背景
    安卓 实现IOS阻尼回弹效果
    安卓 TextToSpeech: speak failed: not bound to TTS engine
    安卓 验证码输入框InputCode(同时支持密码输入)
    安卓 viewpager2动态设置滚动速度
    安卓 节点进度条NodeProgressBar
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10142878.html
Copyright © 2011-2022 走看看