• 组合数学(含二项式反演,特殊数列,置换群)


    资料与前置知识

    必备技能:数论

    容斥计数部分已搬到:容斥&计数

    当小球遇上盒子

    ball1


    组合基础

    组合恒等式

    [nC(n,m)=mC(n-1,m-1) ]

    [C(n,m)=C(n-1,m-1)+C(n-1,m) ]

    [sum_{0<=i<=n}C(n,i)=2^n ]

    [sum_{0<=i<=n}(-1)^i * C(n,i)=0 ]

    [sum_{m<=i<=n}C(i,m)=C(n+1,m+1) ]

    [sum_{0<=i<=p}C(n,i)C(m,p-i)=C(m+n,p) ]

    [sum_{i=0}^n(C_n^i)^2 (= sum_{i=0}^n(C_n^i * C_n^{n-i}) = C_{2n}^n ]

    组合数的算法:

    1. O((n^2)) DP

    2. 当模数为质数时,O(n)阶乘+逆元

    3. 模数较小,n,m巨大时:P3807 【模板】卢卡斯定理【简介】卢卡斯定理

    4. 模数可分解为 Πp^q,且p^q不大时:P4720 【模板】扩展卢卡斯【简介】扩展卢卡斯

    5. 无任何特征,但n, m <= 1e6, M <= 1e9以内时:线性筛将阶乘分解质因数,然后除法 -> 减法,最后乘起来就好

    6. (不常用)对于大阶乘,有一个估算的方法:(n! = sqrt{2 pi n} * (frac{n}{e})^n),其中 (e) 为自然对数的底数。可以依据此算一些东西(当然不能暴力算阶乘),比如 (n!) 的十进制下的位数,就可以转而求 (log_{10}n!),然后变为求 (log_{10} (sqrt{2 pi n} * (frac{n}{e})^n)),这个要好求一些。

    经典模型

    (n) 个无标号球分成 (m) 个有标号组不可为空(插板)

    (n) 个无标号球分成 (m) 个有标号组可以为空(插板)

    (n) 个有标号球分成 (m) 个有标号组可以为空((m^n))

    (n) 个有标号球分成 (m) 个有标号组不可为空(枚举非空组数)

    (n) 个有标号球分成 (m) 个无编号组不可为空(第二类斯特林数)

    (n) 个有标号球分成 (m) 个无编号组可以为空(第二类斯特林数 + 枚举非空组数)

    (n) 个无标号球分成 (m) 个无标号组不可/可以为空(整数划分数)


    长为 (n) 的序列中选择 (m) 个不相邻的元素的方案数

    可以看作从剩下的 (n-m) 个元素所形成的 (n - m + 1) 个空位置中选择 (m) 个空位置的方案数。因此答案为:

    [{n-m+1 choose m} ]

    二项式反演:

    二项式反演

    公式

    二项式反演的主要的三种形式:

    形式一

    [f[n] = sum_{i=0}^n (-1)^iC_n^ig[i] ]

    [g[n] = sum_{i=0}^n (-1)^iC_n^if[i] ]

    最对称了,也是最好背的一个。

    形式二

    [f[n] = sum_{i=0}^n C_n^ig[i] ]

    [g[n] = sum_{i=0}^n(-1)^{n-i}C_n^if[i] ]

    形式三

    [f[n] = sum_{i=n}^m C_{i}^ng[i] ]

    [g[n] = sum_{i=n}^m (-1)^{i-n}C_i^nf[i] ]

    形式二,三一个是 (n-i,C_n^i),一个是 (i-n,C_i^n),主要还是和 (i,n) 的大小关系有关。

    常见套路

    通常是“恰好”与“至少”之间的转换。

    注意,这里的“至少”通常不是由“恰好”以1为系数加和而来,而是包含许许多多的重复计数,否则就可以直接前缀和差分了。

    (f[i]) 表示恰好选择 (i) 个元素的方案数, (g[i]) 表示至少选择 (i) 个元素的方案数。然而,(g[i]) 的计算通常过于无脑,以至于 (1101) 会被 (g[2]) 算三次((1001,1100,0101)),然后才能开始反演。

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

    首先把假的 (k) 转化为真的 (k),然后递推DP之类的...

    假设我们已经知道了选择 (i) 对 A > B ,其它的不管的方案数(dp[i])。这样我们可以无脑地算出 (g[i] = dp[i] * (n-i)!),但是会算重好多。

    (f[i]) 表示恰好有 (i) 对的方案数。则:

    [g[i] = sum_{j=i}^n f[j] * C_j^i ]

    也就是说,(g[i]) 会将 (f[j]) 的每种情况都算重 (C_j^i) 次。

    然后就是二项式反演的套路了。

    [f[i]=sum_{j=i}^n (-1)^{j-i}C_j^ig[j] ]

    (n^2) 计算即可。

    P5505 [JSOI2011]分特产

    同样大致的套路,都是先“无脑”,后推式子反演。

    据说可以用容斥做,但是我刚容斥到第二项就脑壳疼了。

    #2839. 集合计数

    之前曾经用容斥的方法做过这道题,但是推的式子不一样。

    那一次我是考虑当前 (g) 选择的那 (i) 个元素以外再多出那么几个元素,有多少种方案,然后乘上对应的组合数容斥打表。

    这一次我还是按照套路,(g) 的实质分类讨论,其中对于交了 (j) 个的情况,(g) 的计算中一共有 (f[j]) 种情况,并且每一种情况都恰好被计算了 (C_j^i) 次;情况与情况之间无关,可以用加法原理, 然后就是那个老套路了。看来这两种方法应该结果是一样的。

    特殊数列:

    prufer序列

    将一棵无根树进行如下操作:

    将找到编号最小的叶子节点,记录与其相连的节点编号,然后删除掉它。直至只剩两个点。其中记录的编号序列即为该无根树的prufer序列

    显然,大小为 (n) 的无根树的prufer序列长度为 (n - 2).

    无根树与prufer序列是一一对应的。已知一无根树可以求其prufer序列,已知prufer序列可以求其对应的无根树。方法见:P6086 【模板】Prufer 序列,主要是模拟求prufer序列,推测最小叶子节点构造无根树。

    无根树的prufer序列中,一个点的出现次数=其度数-1,因为每个点只有在删除自己时会“消耗”一条连边而不将自己编号记录一遍。

    根据无根树与prufer序列的一一对应的关系,可以将其互相转化,以简化问题。如:n个点的完全图生成树有 (n^{n-2});另外还有:P2624 [HNOI2008]明明的烦恼

    错排数

    枚举最后一个的错排情况(两个位置互相“占用”,或者把 (n)(i) 那里,把 (a_i)(n) 那里)(或者说分类考虑最终答案里面放 (n) 的那个位置的下标是否是 (a_n),然后加法原理),O(n)递推:

    f[n] = f[n - 1] * (n - 1) + f[n - 2] * (n - 1)
    	 = (n - 1)(f[n - 1] + f[n - 2])
    其中,f[0] = 1, f[1] = 0;
    

    Catalan数

    Catalan

    斯特林数:

    实际上斯特林数还可以用于普通幂和阶乘幂之间的转化,不过就比较高级了。

    第一类斯特林数

    (s[n][m]) 表示把 (n) 个有标号元素划分为 (m) 个非空圆排列的方案数。

    [s[n][m] = s[n - 1][m - 1] + s[n - 1][m] * (n - 1) ]

    第二类斯特林数

    (s[n][m]) 表示把 (n) 个有标号元素分成 (m) 个非空集合的方案数。即把 (n) 个元素(有标号)分成 (m) 份(无标号),不能为空。

    [s[n][m] = s[n - 1][m - 1] + s[n - 1][m] * m ]

    然后对比"把 (n) 个元素(有标号)分成 (m) 份(有标号),可以为空"的式子:(m^n)

    然后考虑它们之间的关系:枚举第二种中非空集合的个数:

    [m^n = sum_{i=0}^{m} C_m^i × s[n][i] × i! ]

    然后发现可以二项式反演:

    [s[n][m] * m! = sum_{i=0}^{m} C_m^i × i^n × (-1)^{m-i} ]

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

    (A_i = frac{i^n}{i!})(B_i = frac{(-1)^i}{i!}),那么:

    [s[n][m] = sum_{i=0}^m A_i * B_{m-i} ]

    然后发现对于 (n) 固定的情况, (s[n][m])(A_i)(B_i) 的卷积形式,这样我们就可以 NTT 优化到 (O(nlogn)) 求一批第二类斯特林数了。

    一些小技巧

    [m^n = sum_{i=0}^{m} C_m^i × s[n][i] × i! ]

    对于这个式子我们可以把 (a^k) 这样的数换一种形式:

    [a^k = sum_{i=0}^{a} C_a^i × s[k][i] × i! ]

    然后通常就可以优化一些式子了。比如:P4827 [国家集训队] Crash 的文明世界

    整数划分数

    (n) 划分为 (m) 个正整数的和的方案数:

    [f[n][m] = f[n - 1][m - 1] + f[n - 1][m] ]

    伯努利数

    我们设自然数幂和:

    [S_m(n)=sum_{i=0}^{n-1}i^m ]

    将其用关于 (n)(m+1) 次多项式表示,并在其中定义伯努利数 (B_i):(证明见链接)

    [S_m(n)=dfrac{1}{m+1} sum_{i=0}^{m} {m+1 choose i} B_in^{m+1-i} ]

    伯努利数的递归定义式:

    [sum_{i=0}^{m} {m+1 choose i} B_i = [m=0] ]

    生成函数定义式:

    [B(x)=frac{x}{e^x-1} ]

    具体见链接。

    置换群:

    给有n个珠⼦的项链染⾊,共有m种颜⾊,考虑旋转(或旋转+翻折),求方案数。

    • 找置换(映射)群(集合)

    如何确定自己把置换群找对了?

    1. 不要重复
    2. 要有恒等置换
    3. 要有任两个置换的复合
    4. 要有任何⼀个置换的逆置换
    • burnside引理

    本质不同的项链数 = sigma{每个映射的不动点数目} / |P|

    其中,|P|为置换群大小,通常为旋转0次,1次,2次...n - 1次中的 n 。

    • polya定理
    对于这种只有翻转、旋转的置换,不仅是A到A的映射,还是珠子到珠子的映射。这时候,每个置换其实对应了一个排列,把原来珠子的位置映射到新的珠子的位置。
    对于这种本质上是排列的置换,求不动点的实质就是求这个排列有多少个环。每个排列都是若干个循环的复合:我们把排列位置i上的数字设为p_i,i->pi连一条边,得到的是一个环的森林,每一个环都要染成一样的颜色。总的染色方案数,
    就是颜色数 的 “环的个数” 次方。这个叫做polya定理。
    -by gzz学长
    

    例题:Color

    双倍经验:P4980 【模板】Polya定理

    其实是个推式子题

    polya

    第一张图片注释:

    第二行把g除掉后,i/g和n/g互质,所以i/g有逆元。因此,给定唯一的t(<n/g),都有唯一不同的一个答案,从而得出结论:环的大小为n/g

    color

    第二张图片注释:

    第二个等号:n -> n/g, i -> i/g,因此范围缩小g,到0~(n-1)/g,等价于0~(n/g)-1

    Code:

    inline ll polya(int n) {
    	ll res = 0;
    	for (register int i = 1; i * i <= n; ++i) {
    		if (n % i == 0) {
    			register int g = i;
    			res += quickpow(n, g - 1) * get_phi(n/g) % P;
    			if (i * i != n)	res += quickpow(n, n/g - 1) * get_phi(g) % P;
    			res %= P;
    		}
    	}
    	return res;
    }
    

    Continued...

  • 相关阅读:
    VxWorks固件分析方法总结
    WebGoat系列实验Injection Flaws
    WebGoat系列实验Cross-Site Scripting (XSS)
    WebGoat系列实验Denial of Service & Insecure Communication
    WebGoat系列实验Buffer Overflows & Code Quality & Concurrency
    WebGoat系列实验Authentication Flaws
    WebGoat系列实验Access Control Flaws
    20155224 聂小益 《基于Arm实验箱的接口测试和应用》 课程设计报告
    实验补交的链接
    2017-2018-2 20155224『网络对抗技术』Exp4:恶意代码分析
  • 原文地址:https://www.cnblogs.com/JiaZP/p/13618607.html
Copyright © 2020-2023  润新知