容斥

二项式定理

[(a + b) ^ n = sum_{i=0}^n inom{n}{i} cdot a ^ {i} cdot b ^ {n - i} ]

证明:

(n)((a + b)), 考虑对于最终 (a ^ k cdot b ^ {n - k}) 的贡献:
每一项选 (a)(b) 然后相乘累加, 那么总共从 (n) 项里选 (k)(a), 其余都选 (b)

常见带入:

[(x + 1) ^ n = sum_{i=0}^n inom{n}{i} x ^ i ]

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

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

二项式反演

[f_n = sum_{i=0}^n (-1)^i {n choose i} g_i Leftrightarrow g_n = sum_{i=0}^n (-1)^i {n choose i} f_i ]

下面这个式子的 (g(i)) 当做上面的 (g(i) cdot (-1) ^ i), 然后带入易得

[f_n = sum_{i=0}^n {n choose i} g_i Leftrightarrow g_n = sum_{i=0}^n (-1)^{n-i} {n choose i} f_i ]

证明第一个:

充要条件, 那么左边可推出右边, 右边可推出左边

由于这两个式子对称, 这里就偷懒只证明一个方向好了
例: 充分性: 左 (Rightarrow)

[egin{aligned} g_n & = sum_{i=0}^n (-1)^i inom{n}{i} sum_{j=0}^i (-1)^j inom{i}{j} g_j \ & = sum_{i=0}^n sum_{j=0}^i (-1)^{i + j} inom{n}{i} inom{i}{j} g_j end{aligned} ]

写在一个矩阵里比较直观(对于推导不是必要的), 观察右下角即为 (g_n) 与等式左边相同, 若要成立说明前面一片是 (0):

[egin{bmatrix} & inom{n}{0}inom{0}{0} g_0 \ & -inom{n}{1}inom{1}{0} g_0 & inom{n}{1}inom{1}{1} g_1 \ & inom{n}{2}inom{2}{0} g_0 & -inom{n}{2}inom{2}{1} g_1 & inom{n}{2}inom{2}{2} g_2\ & vdots & vdots & ddots & \ & (-1)^ninom{n}{n}inom{n}{0} g_0 & (-1)^{n+1}inom{n}{n}inom{n}{1} g_1 & dots & (-1)^{2n}inom{n}{n}inom{n}{n} g_n\ end{bmatrix} ]

改成竖向求和

[egin{aligned} g_n & = sum_{i=0}^n g_i sum_{j=i}^n inom{n}{i} inom{i}{j} (-1)^{i+j}\ & = sum_{i=0}^n g_i inom{n}{j} sum_{j=i}^n inom{n-i}{j-i} (-1) ^ {i + j} end{aligned} ]

解释一下组合数: (i in j in n), 画一个集合图可得
然后最后面一段像是二项式定理, 把 (j) 换元成原来的 (j-i) 比较直观 (换元可以参考上面的矩阵的规律)

[egin{aligned} g_n & = sum_{i=0}^n g_i inom{n}{j} sum_{j=0}^{n - i} inom{n-i}{j} (-1) ^ {j} \ & = sum_{i=0}^n g_i inom{n}{j} (-1 + 1) ^ {n-i} \ & = sum_{i=0}^n g_i inom{n}{j} [i = n] \ & = g_n end{aligned} ]

min-max 容斥

(max(S), min(S)) 分别表示 (S) 中的最大,最小元素

那么有这样两个式子:

[egin{cases} max(S) & = sum_{T subseteq S} (-1) ^ {|T| - 1} min(T) \ min(T) & = sum_{T subseteq S} (-1) ^ {|T| - 1} max(T) \ end{cases} ]

证明:

第一个:

将元素从大到小排序 ({a_1, a_2, dots, a_n}), 当 (a_{x + 1}) 作为 (min(T)) 时,
他的系数是 (sum_{i=0}^x inom{x}{i} (-1) ^ {i + 1 - 1}) , 这是 ((-1 + 1) ^ x) 的二项式展开,
那么当 (x = 0) 时系数为 (1) 否则为 (0), 即 (max(S) = min({ a_1 }))

第二个:
从小到大排序, 其余一样

kth min-max 容斥

(max_{k}(S), min_{k}(S)) 分别为 (S) 中第 (k) 大/小 的元素
(max_k(S) = sum_{T subseteq S} F(|T|) min(T)), 求得这个系数 (F(|T|))

模仿上面的套路, 尝试用 (min(T)) 来表示 (max_{k}(S)) ((min_{k}(S)) 同理)
将元素从大到小排序 ({a_1, a_2, dots, a_n}), 当 (a_{x + 1}) 作为 (min(T)) 时,
使得当 (x = k - 1) 时系数为 (1) 否则为 (0)

根据上面的关系可得 (sum_{i=0}^x inom{x}{i} cdot F(i + 1) = [x = (k - 1)])

套用二项式反演 (f(i) = F(i + 1), g(i) = [i = (k - 1)])

[sum_{i=0}^x inom{x}{i} cdot F(i + 1) = [x = (k - 1)] Leftrightarrow F(x + 1) = sum_{i=0}^x (-1) ^ {x - i} cdot inom{x}{i} [i = (k - 1)] ]

[F(x + 1) = (-1) ^ {x - (k - 1)} cdot inom{x}{k - 1} ]

所以

[max_{k}(S) = sum_{T subseteq S} (-1) ^ {|T| - k} inom{|T| - 1}{k - 1} min(T) ]

同理

[min_{k}(S) = sum_{T subseteq S} (-1) ^ {|T| - k} inom{|T| - 1}{k - 1} max(T) ]

例题

[HDU4336]Card Collector <min-max 容斥>

题意:
给出每种卡牌出现的概率(和为 1 , (n le 20)), 每买一次按上述概率抽卡, 求买到所有卡的期望次数

Sol:
(E(max(S))) 为买到 (S) 中剩下的最后一张卡的期望次数, 即答案(理解)
(E(min(S))) 为买到 (S) 中第一张卡的期望次数, 显然是 (frac{1}{sum_{i in T} p_i})

[E(max(S)) = sum_{T subseteq S} (-1) ^ {|T| - 1} min(T) ]

预处理 + 枚举子集

typedef double LDB;

int n;

const int MAXN = (1 << 20) + 10;
int cnt[MAXN], d[MAXN];
LDB p[30], mnp[MAXN];

int lowbit(int x) { return x & (-x); } 

int main()
{
    while (scanf("%d", &n) != EOF)
    {
	d[1] = 0;
	for (int i = 1; i <= n; ++ i) 
	{
	    scanf("%lf", &p[i]);
	    d[1 << i] = i;
	}
	int S = (1 << n) - 1;
	mnp[0] = cnt[0] = 0;
	for (int i = 1; i <= S; ++ i)
	{
	    mnp[i] = mnp[i & (i - 1)] + p[d[lowbit(i)] + 1];
	    cnt[i] = cnt[i & (i - 1)] + 1;
	}
	LDB ans = 0;
	for (int T = S; T != 0; T = (T - 1) & S)
	    ans += (cnt[T] % 2 == 1 ? 1 : -1) * 1 / mnp[T];
	printf("%lf
", ans);
    }
    return 0;
}

BZOJ4036: [HAOI2015]按位或

刚开始你有一个数字0,每一秒钟你会随机选择一个[0,2^n-1]的数字,与你手上的数字进行或(c++,c的|,pascal
的or)操作。选择数字i的概率是p[i]。保证0<=p[i]<=1,Σp[i]=1问期望多少秒后,你手上的数字变成2^n-1。

Sol:

先套用 min-max, (E(max(S))) 表示到达最后一个元素的期望, (E(min(S))) 到达第一个元素的期望

考虑 (E(min(S))) 怎么求, 当没有到达第一个元素的时候, 当前到达的集合和 (S) 是没有交集的, 这时需要或上一个与 (S) 有交集的数即可
于是发现既然没有到达之前都是无交集, 而且此时选择的数的概率仍然是这样, 那么无论何时概率都是 (sum_{t cap S e emptyset} p[t]),
也就是说和上一题一样

在考虑如何快速求这个

[E(min(S)) = sum_{t cap S e emptyset} p[t] ]

尝试转化成 FWT 能用的形式, 设 sum[S] = (sum_{t cap S e emptyset} p[t])

[egin{aligned} sum[S] & = totsum - sum_{t cap S = emptyset} p[t] \ & = totsum - sum_{complement t cap S = S} p[t] end{aligned} ]

后面那段就是 FWT and 的通式, 一遍 FWT 求得

void FWT(double * a, int len)
{
    // FWT(A) = merge(FWT(A0) + FWT(A1), FWT(A1)) ;
    for (int mid = 1; mid < len; mid <<= 1)
	for (int i = 0; i < len; i += (mid << 1))
	    for (int j = 0; j < mid; ++ j)
		a[i + j] += a[i + j + mid];
}

int main()
{
    n = in();
    int S = (1 << n) - 1;
    for (int i = 0; i <= S; ++ i) scanf("%lf", &p[i]), totsum += p[i];
    for (int i = 1; i <= S; ++ i)
    {
	int sub = i & (i - 1);
	cnt[i] = cnt[sub] + 1;
    }
    for (int i = 0; i <= S; ++ i)
	if (i < S - i) swap(p[i], p[S - i]);
    FWT(p, S + 1);
    double ans = 0;
    for (int T = S; T != 0; T = (T - 1) & S)
    {
	if (fabs(totsum - p[T]) <= 0) return printf("INF
"), 0;
	ans += (cnt[T] % 2 == 1 ? 1 : -1) * 1.0 / (totsum - p[T]);
    }
    printf("%.6lf
", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/Kuonji/p/12052656.html