Min-Max 容斥
亿些废话
上课听 lf 说到「莫比乌斯反演」,「FWT/FMT」,「生成函数」这些什么的都讲过我就很头大,数学这坑是得有多大啊。
不过 lf 说不久后就开始复习网络流,好歹算是有点空闲时间可以补数学了。
前置芝士
要会基本的容斥,以及二项式定理。
如果你不会的话可以看看我写的二项式反演和广义容斥原理,上面两个东西在这两篇博客中都有讲到。
Min-Max 容斥
也叫「最值反演」,就是在你知道一个集合所有子集的最小值(或最大值)时,可以通过它们反演出这个集合的最大值。
听起来很弱智对吧,从直觉上来说你可以直接这么干:
$$ \begin{aligned} \max(S) = \max\limits_{T \in S}\left\{\min(T)\right\}\\ \min(S) = \min\limits_{T \in S}\left\{\max(T)\right\} \end{aligned} $$
你说得对,但是 Min-Max 容斥长成这个样子:
$$ \begin{aligned} \max(S) = \sum\limits_{T \in S}(-1)^{|T| - 1}\min(T)\\ \min(S) = \sum\limits_{T \in S}(-1)^{|T| - 1}\max(T) \end{aligned} $$
第一眼觉得这个柿子好神奇,可以把最值转化成求和。(事实上 Min-Max 容斥神奇的原因就是这个。)
让我们证明一下(以通过最小值反演出最大值为例):
首先将集合内的数从大到小排序,现在将它们记为 $s_{1}, s_{2}, s_{3}, \cdots, s_{|S|}(\forall i\in\left[1, |S|\right) s_{i} \geqslant s_{i + 1})$。
依次考虑每个数在上面的柿子中的贡献。
一个数要想作为最小值被计算,那么在某个子集中,最小值会在其中出现,并且剩下的数只能是在这个最小值前面的数,否则最小值就不是这个数了。
所以我们可以写出第 $i$ 个数的贡献:
$$ \begin{aligned} &\sum\limits_{T \in \left\{s_{1}, s_{2}, \cdots, s_{i - 1}\right\}}(-1)^{|T| + 2}s_{i}\\ =&s_{i}\sum\limits_{T \in \left\{s_{1}, s_{2}, \cdots, s_{i - 1}\right\}}(-1)^{|T| + 2}\\ \end{aligned} $$
发现后面那一坨柿子和具体的 $T$ 集合长成什么样无关,我们只用考虑 $|T|$ 即可,于是改写成下面这种形式:
$$ \begin{aligned} &s_{i}\sum\limits_{j = 0}^{i - 1}\binom{i - 1}{j}(-1)^{j + 2}\\ =&s_{i}\sum\limits_{j = 0}^{i - 1}\binom{i - 1}{j}(-1)^{j}\\ \end{aligned} $$
然后发现后面这一坨可以用二项式定理化成 $(1 - 1)^{i - 1} = [i = 1]$。
于是,$s_{1}$ (也就是最大值)的贡献为 $s_{1}$,而其它数的贡献为 $0$。证毕。
最小值类似。
那么这个看起来很弱智并且时间复杂度还不优的东西有什么用呢。
根据期望的线性性,Min-Max 容斥在期望上也是成立的,所以:
$$ \begin{aligned} E\big(\max(S)\big) = \sum\limits_{T \in S}(-1)^{|T| - 1}E\big(\min(T)\big)\\ E\big(\min(S)\big) = \sum\limits_{T \in S}(-1)^{|T| - 1}E\big(\max(T)\big) \end{aligned} $$
于是在遇到求「最大值的期望」不方便的时候,可以尝试求「最小值的期望」来容斥出「最大值的期望」。
既然这个东西是容斥,那它是不是也满足广义容斥原理呢?答案是肯定的,这种情况就是求 kth max/kth min 了。
这个东西等我以后再来补吧。
例题
都是拿来求期望的,所以还需要一定的概率/期望 dp 基础。
「HDU 4336」Card Collector
题目大意:有 $n$ 种卡片,第 $i$ 种卡片在一包零食中出现的概率为 $p_{i}$,并且每包零食中至多出现一张卡片,问你集齐所有的卡片需要购买零食数量的期望。
这道题有一个 $\mathcal{O}(n2^{n})$的状压 dp 做法,但是我不讲。
考虑 Min-Max 容斥:
我们把买来的零食按买入的顺序排成一排,令 $t_{i}$ 表示第 $i$ 种卡片第一次出现是在第 $t_{i}$ 包零食中,于是我们就要求 $E\big(\max\limits_{1 \leqslant i \leqslant n}t_{i}\big)$。
但是直接求「最大值的期望」并不方便,用 Min-Max 容斥转化成求「最小值的期望」。
于是有:
$$ E\big(\max(S)\big) = \sum\limits_{T \in S}(-1)^{|T| - 1}E\big(\min(T)\big) $$
直接枚举子集 $T$,现在考虑求 $E\big(\min(T)\big)$,其本质就是问:你第一次拿到属于这个集合的卡片所要买的零食数量。
买一包零食,我们拿到属于这个集合的卡片的概率为 $\sum\limits_{i \in T}p_{i}$,现在来求期望。
(其实这里写为 $\sum\limits_{i \in T}p_{i}$ 是不够严谨的,因为 $T$ 集合里面是 $t_{i}$ 而不是 $i$,但是我一时没想到更好的表达方法于是就这么写了,相信大家能看懂。)
我推到这里就不会了,因为这种看起来可以无限进行下去的东西对我来说实在太抽象了,尽管我知道它是收敛的。问了一下 cgy,他给了我两种做法,我觉得都挺容易理解的,于是就都写一下:
- 直接暴力地写成求和式。
(下文的 $p$ 默认为 $\sum\limits_{i \in T}p_{i}$。)
我们其实是要求:
$$ \sum\limits_{i = 1}^{+\infty}(1 - p)^{i - 1} \times p \times i $$
(如果写成 $\sum\limits_{i = 1}^{+\infty}(1 - p)^{i - 1} \times p$ 的话那想必大家都知道是 $1$,因为概率和为 $1$)
考虑把 $p$ 提到外面来:
$$ p \times \sum\limits_{i = 1}^{+\infty}(1 - p)^{i - 1} \times i $$
现在重心转移到求后面这一坨柿子上面,我们把它的每一项写下来,排成一个数列:
$$ 1, 2(1 - p), 3(1 - p)^{2}, 4(1 - p)^{3}, \cdots $$
给它减去一个 $\sum\limits_{i = 1}^{+\infty}(1 - p)^{i - 1}$(一个等比数列),数列就变成了:
$$ 0, (1 - p), 2(1 - p)^{2}, 3(1 - p)^{3}, \cdots $$
现在,给它除一个 $1 - p$,变成:
$$ 1, 2(1 - p), 3(1 - p)^{2}, 4(1 - p)^{3}, \cdots $$
惊奇地发现它就是原来的柿子!
假设 $A = \sum\limits_{i = 1}^{+\infty}(1 - p)^{i - 1} \times i$,于是有:
$$ \dfrac{A - \sum\limits_{i = 1}^{+\infty}(1 - p)^{i - 1}}{1 - p} = A $$
用等比数列求和公式把柿子化成:
$$ \begin{aligned} \dfrac{A - \dfrac{1}{p}}{1 - p} &= A\\ A - \dfrac{1}{p} &= (1 - p)A\\ pA &= \dfrac{1}{p}\\ A &= \dfrac{1}{p^{2}}\\ \end{aligned} $$
(不会等比数列求和的可以去看百度百科。)
最后把原来提出去的 $p$ 乘回来就好,所以 $E(T)= \dfrac{1}{p}$。我认为这个东西可以当作结论来记,也不复杂。
- 利用整个过程的相似性(可以这么说吧)来「递归」计算。
假设我们第一次就拿到了想要的卡片,概率为 $p$。
如果没有拿到,那么概率为 $1 - p$。
如果正好是这 $1 - p$ 的概率,我们经过了这一步得到了什么呢?
什么也没得到,所以回到了起点。
回到了起点过后,我们什么也没改变,所以概率还是一样的,还是有 $p$ 的概率拿到想要的卡片,有 $1 - p$ 的概率再次回到起点。
所以就可以写出这么个柿子来:
$$ \begin{aligned} E(T) &= p + (1 - p)(E(T) + 1)\\ E(T) &= p + (1 - p)E(T) + 1 - p\\ pE(T) &= 1\\ E(T) &= \dfrac{1}{p}\\ \end{aligned} $$
好像很厉害的样子!
于是这个问题就得到了解决!
用一些小技巧可以把时间复杂度优化到 $\mathcal{O}(2^{n})$,不过好像没太大意义?
放个代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
double ans, p[25], sum[1 << 20];
int gsm(int x) {return x & 1 ? -1 : 1;}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
while(cin >> n) {
for(int i = 1; i <= n; ++i) cin >> p[i];
sum[0] = 0.0, ans = 0.0;
for(int i = 1; i < (1 << n); ++i) {
sum[i] = sum[i ^ (i & -i)] + p[__lg(i & -i) + 1];
ans += gsm(__builtin_popcount(i) - 1) / sum[i];
}
cout << fixed << setprecision(4) << ans << '\n';
}
return 0;
}
[HAOI2015] 按位或
这两个东西其实差别不大,一样的套路转化一下问题就是基本一模一样的了。
但是你会发现在求 $E\big(\min(T)\big)$ 的时候,$T$ 的概率和 $p$ 并不好计算,这个时候就得用到高维前缀和/子集前缀和了(或者叫 SOSdp,$\texttt{Sum Over Subsets Dynamic Programming}$)。
这个东西暂时先不写,等我有空来了。
或者你硬是要用 FMT 或者 FWT 也行。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
double ans, p[25], sum[1 << 20];
int gsm(int x) {return x & 1 ? -1 : 1;}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 0; i < (1 << n); ++i) {
cin >> sum[i];
for(int j = 0; j < n; ++j) {
if((i >> j) & 1) p[j] += sum[i];
}
}
for(int i = 0; i < n; ++i) {
if(p[i] == 0.0) {
cout << "INF";
return 0;
}
}
for(int i = 0; i < n; ++i) {
for(int j = 0; j < (1 << n); ++j) {
if((j >> i) & 1) {
sum[j] += sum[j ^ (1 << i)];
}
}
}
for(int i = 1; i < (1 << n); ++i) {
ans += gsm(__builtin_popcount(i) + 1) / (1 - sum[((1 << n) - 1) ^ i]);
}
cout << fixed << setprecision(10) << ans;
return 0;
}
本文来自博客园,作者:A_box_of_yogurt,转载请注明原文链接:https://www.cnblogs.com/A-box-of-yogurt/p/18016396