一些组合数学
-
错排
\(f(x)\) 含义为放置的所有数中有 \(x\) 个数错位排列的情况数。
假定当前准备放置第 \(x\) 个数。初始时将第 \(x\) 个数放在标号为 \(x\) 的位置。此时需要将 \(x\) 与前 \(x-1\) 个数中的某一个交换
若前 \(x-1\) 个数均错位排列,那么目前有 \(x-1\) 种交换方案,即 \(f(x) \leftarrow (x-1)*f(x-1)\)
若前 \(x-1\) 个数中仅有一个没有错位排列,那么必须将第 \(x\) 个数与那个没有错排的数交换。共有 \(n-1\) 种一个数没有错排的情况。那么, \(f(x) \leftarrow (x-1)*f(x-2)*1\) 。
若前 \(x-1\) 个数中存在多于一个数没有错位排列,此时无法通过一次交换使得所有数均错位排列。
综上,\(f(x) = (x-1)(f(x-1)+f(x-2))\)
-
一些二项式定理的推论
\(\sum\limits_{i=0}^n {\dbinom{n}{i}} = 2^n \ \ \ \ \ \ \ \ \sum\limits_{i=0}^n (-1)^i {\dbinom{n}{i}} = 0\)
-
\(\text{Catalan Number}\) 式子
\(H(x) = \begin{cases} 1 & x \leq 2 \\ \frac{\binom{2n}{n}}{n+1} & x>2 \\ \sum\limits_{i=1}^{n}{H(i-1)*H(x-i)} & x>2 \end{cases}\)
-
\(\text{Stirling Number}\) 式子
第一类(stirling轮换数)
\(\begin{bmatrix} n \\ k \end{bmatrix}\) 表示将 \(n\) 个数划分成 \(k\) 个圆排列的方案数
将第 \(n\) 个数划分为一个新的排列,即 \(\begin{bmatrix} n \\ k \end{bmatrix} \leftarrow \begin{bmatrix} n-1 \\ k-1 \end{bmatrix}\)
将第 \(n\) 个数插入到一个已有的排列中。因为是圆排列,所以插入到 \(n-1\) 个已有元素中的任意一个的后面都可以计入答案。 \(\begin{bmatrix} n \\ k \end{bmatrix} \leftarrow (n-1) \begin{bmatrix} n-1 \\ k \end{bmatrix}\)
性质: \(n! = \sum\limits_{i=0}^{n} {\begin{bmatrix} n \\ i \end{bmatrix}}\)
第二类(stirling子集数)
\(\begin{Bmatrix} n \\ k \end{Bmatrix}\) 表示将 \(n\) 个数划分成 \(k\) 个集合的方案数
将第 \(n\) 个数划分为一个新的集合,即 \(\begin{Bmatrix} n \\ k \end{Bmatrix} \leftarrow \begin{Bmatrix} n-1 \\ k-1 \end{Bmatrix}\)
将第 \(n\) 个数插入到一个已有的集合中,即 \(\begin{Bmatrix} n \\ k \end{Bmatrix} \leftarrow (k-1) \begin{Bmatrix} n-1 \\ k \end{Bmatrix}\)
性质: $x^n = \sum\limits_{i=0}^{x} { {\begin{Bmatrix} n \ i \end{Bmatrix}} * i! * \dbinom{x}{i} } $
-
\(\text{Min-Max}\) 容斥
证明:
设 \(A_i\) 表示对 \(S\) 集合排序后第 \(i\) 大的数。
若 \(min(S)=A_1\) ,则 \(S = \{A_1\}\) 。
对于这种情况,对答案的贡献为 \((-1)^{1+1}A_1 = A_1\) 。
若 \(min(S) = A_k \ (k > 1)\) ,则 \(S = \{\dots A_a \dots A_b \dots A_c \dots A_k\}\) 。即, \(A_1\) 到 \(A_{k-1}\) 所有元素的某个子集再加上 \(A_k\) 本身。
对于这种情况,观察可知 \(A_1\) 到 \(A_k\) 所有元素的子集中,大小为奇数的集合与大小为偶数的集合数量相等。因此,对答案的贡献为 \(0\) 。
综上,答案恰为 \(A_1\) ,即 \(max(S)\) 。
拆位考虑,答案即为 \(E(max\{T\})\) ,其中 \(E(x)\) 表示 \(x\) 中元素的最晚出现时间的期望。注意, \(x\) 是一个二进制数,代表一个集合。若其中第 \(i\) 位为 \(1\) 则表示集合中存在 \(i\) 。
直接求解较为困难,故可以转为求解 \(E(min\{T\})\) ,再容斥得出答案。
$E(max{T}) = \sum\limits_{T \subseteq x} {(-1)^{|T|+1}E(min{T})} \ \ $ 那么,如果对于任意集合 \(T\) ,可以迅速求出 \(E(min\{T\})\) ,本题就得到解决。
\(E(min\{T\}) = \dfrac{1}{\sum\limits_{G \cap T \ne \empty} {P_G}}\) 。分母的那个sum求解较为困难,但发现分母可以当成 \(G\) 的补集的子集和;而子集和可以预处理的出。于是本题得解。
#include <bits/stdc++.h>
using namespace std;
#define M 1100005
int n, popcnt[M], flag[M];
double ans, p[M], sum[M];
int main()
{
scanf("%d", &n);
for (int i = 0; i < (1<<n); i++)
scanf("%lf", &p[i]);
for (int i = 0; i < (1<<n); i++)
{
popcnt[i] = popcnt[i>>1] + (i&1);
flag[i] = (((popcnt[i]+1)&1) ? -1 : 1);
}
for (int len = 2; len <= (1<<n); len <<= 1)
for (int i = 0; i < (1<<n); i += len)
for (int j = 0; j < (len>>1); j++)
p[i+j+(len>>1)] += p[i+j]; // 预处理子集和
double ans = 0;
for (int sta = 1; sta < (1<<n); sta++)
if (1-p[((1<<n)-1) ^ sta] > 1e-10)
ans += 1.0 * flag[sta] / (1-p[((1<<n)-1) ^ sta]); // min-max容斥
if (ans < 1e-10) puts("INF");
else printf("%.11lf\n", ans);
return 0;
}
\(\text{Kth-Min-Max}\) 容斥
证明略。
例:重返现世
\(\text{Kth-Min-Max}\) 板子。
对所有原料的期望出现时间排序,那么答案为出现时间第 \(k\) 小的元素的出现时间。(即,第 \(n-k+1\) 大)
本题的难点在于加速运算。发现 \(n \le 1000\) ,故直接枚举子集不可取。

浙公网安备 33010602011771号