Min-Max容斥及其推廣和應用

概念

Min-Max容斥,又稱最值反演,是一種對於特定集合,在已知最小值或最大值中的一者狀況下,求另外一者的算法。php

例如:算法

$$max(a,b)=a+b-min(a,b) \\\ max(a,b,c)=a+b+c-min(a,b)-min(a,c)-min(b,c)+min(a,b,c)$$數組

顯然,將全部數取相反數,易知用最大值求最小值的公式與用最小值求最大值的公式形式相同。如下只討論用最小值求最大值的方法。函數

形式

記 $Max(S)$ 表示集合 $S$ 的最大值,$Min(S)$ 表示集合 $S$ 的最小值,則:
$$
Max(S)=\sum\limits_{T\subset S,T\neq \phi}(-1)^{|T|-1}Min(T)
$$spa

推導

設存在一個以集合大小爲自變量的函數 $f$ 知足 $Max(S)=\sum\limits_{T\subset S,T\neq \phi}f(|T|)Min(T)$ 。code

記 $S$ 中元素從大到小排列爲 $x_1,x_2,...,x_m$ ,則對於 $x_i$ ,其在左側的貢獻爲 $[i=1]$ ,在右側的貢獻爲 $\sum\limits_{j=0}^{i-1}{i-1\choose j}f(j+1)$ 。get

若等式成立,則必有 $[i=1]=\sum\limits_{j=0}^{i-1}{i-1\choose j}f(j+1)$ 。string

設 $F(i)=[i+1=1]$ (即 $[i=1]=F(i-1)$ ),$G(i)=f(i+1)$ ,則 $F(i)=\sum\limits_{j=0}^{i}{i\choose j}G(j)$ 。it

進行二項式反演,得 $G(i)=\sum\limits_{j=0}^{i}(-1)^{i-j}{i\choose j}F(j)=(-1)^i$ 。io

故 $f(i)=G(i-1)=(-1)^{i-1}$ 。

所以構形成立,故:
$$
Max(S)=\sum\limits_{T\subset S,T\neq \phi}(-1)^{|T|-1}Min(T)
$$

另外一種證實

考慮等式右側,記最小值爲 $x_i$ ,則:

  • 當 $i=1$ 時,貢獻爲 $1$ ;
  • 當 $i\neq 1$ 時,則 $x_1$ 有選和不選兩種方案,這兩種方案一一對應且係數恰爲相反數,故總貢獻爲 $0$ 。

故右側的總和就是 $x_1=Max(S)$ 。

推廣

記 $kMax(S)$ 表示集合 $S$ 的第 $k$ 大值,則:
$$
kMax(S)=\sum\limits_{T\subset S,|T|\ge k}(-1)^{|T|-k}{|T|-1\choose k-1}Min(T)
$$

推導

設存在一個以集合大小爲自變量的函數 $g$ 知足 $kMax(S)=\sum\limits_{T\subset S,T\neq \phi}g(|T|)Min(T)$ 。

記 $S$ 中元素從大到小排列爲 $x_1,x_2,...,x_m$ ,則對於 $x_i$ ,其在左側的貢獻爲 $[i=k]$ ,在右側的貢獻爲 $\sum\limits_{j=0}^{i-1}{i-1\choose j}g(j+1)$ 。

若等式成立,則必有 $[i=k]=\sum\limits_{j=0}^{i-1}{i-1\choose j}g(j+1)$ 。

設 $F(i)=[i+1=k]$ (即 $[i=k]=F(i-1)$ ),$G(i)=g(i+1)$ ,則 $F(i)=\sum\limits_{j=0}^{i}{i\choose j}G(j)$ 。

進行二項式反演,得 $G(i)=\sum\limits_{j=0}^{i}(-1)^{i-j}{i\choose j}F(j)=(-1)^{i-k+1}{i\choose k-1}$ 。

故 $f(i)=G(i-1)=(-1)^{i-k}{i-1\choose k-1}$ 。

所以構形成立,故:
$$
kMax(S)=\sum\limits_{T\subset S,|T|\ge k}(-1)^{|T|-k}{|T|-1\choose k-1}Min(T)
$$

應用

Min-Max容斥及其推廣經常使用於解決「都出現的指望時間」問題,處理方法:

記 $t_i$ 表示第 $i$ 個元素的出現時間,則:

  • $Max(S)$ 表示 $S$ 中 $t$ 的最大值,即全部元素出現時間的最大值,即全部元素都出現的時間;
  • $Min(S)$ 表示 $S$ 中 $t$ 的最小值,即全部元素出現時間的最小值,即至少有一個出現的時間。

根據Min-Max容斥,有 $Max(S)=\sum\limits_{T\subset S,T\neq \phi}(-1)^{|T|-1}Min(T)$ 。

對左右同時取指望,因爲線性,指望能夠直接放到求和符號裏面,即 $E(Max(S))=\sum\limits_{T\subset S,T\neq \phi}(-1)^{|T|-1}E(Min(T))$ 。

容易發現 $E(Min(T))$ 求起來十分容易:當單位時間出現 $T$ 中至少一個的機率爲 $p$ ,則出現 $T$ 中至少一個的指望時間爲 $\frac 1p$ 。

因而經過公式便可求出 $Max(S)$ ,即全部元素都出現的指望時間。

對於Min-kMax容斥同理。

寫法

若是隻須要求出 $Max(U)$ ,即全集的最大值的話,只須要計算每一個本身對全集的貢獻便可。

若是要對全部 $S$ 求 $Max(S)$ 的話(儘管彷佛還沒遇到過),一種較快的方法是用按位分治來代替枚舉子集。有兩種經常使用寫法,它們稍加處理就能夠變成公式中的形式。

寫法一

for(i = 1 ; i < (1 << n) ; i <<= 1)
    for(j = 0 ; j < (1 << n) ; j ++ )
        if(j & i)
            f[j] -= f[i];

此時係數是 $(-1)^{|S|-|T}$ .

寫法二

for(i = 1 ; i < (1 << n) ; i <<= 1)
    for(j = 0 ; j < (1 << n) ; j ++ )
        if(j & i)
            f[j] = f[i] - f[j];

此時係數是 $(-1)^{|T|}$ 。

例題

[hdu4336]Card Collector

題目大意

有 $n$ 種卡片,每次購買有 $p_i$ 的機率買到第 $i$ 種,求使得每種都買到的指望購買次數。

$1\le n\le 20$ 。

題解

Min-Max容斥基礎題,參見上面的 「應用」 部分。

對於本題,有 $Min(S)=\frac 1{\sum\limits_{i\in S}p_i}$ ,而後套用 $Min-Max$ 容斥的公式便可。

時間複雜度 $O(2^n)$ 。

#include <cstdio>
#define N 1100010
int cnt[N];
double p[N] , f[N];
int main()
{
    int n , i , j;
    double ans;
    while(~scanf("%d" , &n))
    {
        ans = 0;
        for(i = 0 ; i < n ; i ++ ) scanf("%lf" , &p[1 << i]);
        for(i = 1 ; i < (1 << n) ; i ++ ) f[i] = f[i - (i & (-i))] + p[i & (-i)] , cnt[i] = cnt[i - (i & -i)] + 1;
        for(i = 1 ; i < (1 << n) ; i ++ ) ans += ((cnt[i] & 1) ? 1 : -1) / f[i];
        printf("%lf\n" , ans);
    }
    return 0;
}

[bzoj4036]按位或

題目大意

你初始有數字 $0$ ,每次操做會隨機選擇 $[0,2^n-1]$ 的一個數字與你的數字進行按位或運算,選到數 $i$ 的機率爲 $p_i$ 。求使得你的數字變爲 $2^n-1$ 的指望操做次數。

$1\le n\le 20$ 。

題解

和上一題相似,問題轉化爲計算 $Min(S)$ ,即須要求出全部與 $S$ 有公共元素(取與不爲 $0$ )的 $p$ 之和。

正難則反,考慮求全部與 $S$ 無公共元素的 $p$ 之和,即 $S$ 的補集 $2^n-1-S$ 的全部子集的 $p$ 之和,使用按位分治來解決。

最後套公式計算便可。無解的斷定經過判斷是否某一位都存在一個 $p\neq 0$ 的元素來處理。

時間複雜度 $O(n\times 2^n)$ 。

代碼

#include <cstdio>
#include <algorithm>
using namespace std;
double p[1100010];
int cnt[1100010];
int main()
{
    int n , i , j;
    double ans = 0;
    scanf("%d" , &n);
    for(i = 0 ; i < (1 << n) ; i ++ ) scanf("%lf" , &p[i]);
    for(i = 1 ; i < (1 << n) ; i ++ ) cnt[i] = cnt[i - (i & -i)] + 1;
    for(i = 1 ; i < (1 << n) ; i <<= 1)
    {
        for(j = 0 ; j < (1 << n) ; j ++ )
            if((j & i) && p[j])
                break;
        if(j == (1 << n))
        {
            puts("INF");
            return 0;
        }
    }
    for(i = 1 ; i < (1 << n) ; i <<= 1)
        for(j = 0 ; j < (1 << n) ; j ++ )
            if(j & i)
                p[j] += p[j ^ i];
    for(i = 1 ; i < (1 << n) ; i ++ ) ans += ((cnt[i] & 1) ? 1 : -1) / (1 - p[(1 << n) - 1 - i]);
    printf("%.8lf\n" , ans);
    return 0;
}

[luogu4707]重返現世

題目大意

有 $n$ 種物質,每單位時間會隨機生成一種物質,生成第 $i$ 種物質的機率爲 $\frac{p_i}m$ 。求得到 $k$ 種物質的指望時間。

$1\le n\le 1000$ ,$1\le m\le 10000$ ,$1\le k\le n$ ,$p_i$ 爲整數且 $\sum\limits_{i=1}^np_i=m$ ,$n-k\le 10$ 。

題解

得到 $k$ 種物質,至關於求全部得到時間中第 $n-k+1$ 大的,問題轉化爲Min-kMax容斥問題。方便起見,如下令 $q=n-k+1$ ,則有 $1\le q\le 11$ 。

因爲 $n$ 有 $1000$ 之大,使用前兩道題的子集統計方法顯然會直接暴斃。

思考:儘管咱們的集合選取方案有 $2^n$ 種,但每種的 $Min(S)$ 只和 $\sum\limits_{i\in S}p_i$ 有關,所以狀態數其實只有 $m$ 種。

一個比較顯然的思路是設 $f_{i,j,l}$ 表示前 $i$ 種物質選出 $j$ 種,湊齊 $\sum p=l$ 的方案數,然而數據範圍過大,沒法經過此題。

到此爲止,咱們還有一個條件沒有用到:$q\le 11$ 。

考慮在已知 $f_{i,j,l}$ 後答案的計算,貢獻爲 $(-1)^{j-q}{j-1\choose q-1}\times \frac ml\times f_{i,j,l}$ 。對於前面的部分,運用組合數公式,有:
$$
(-1)^{j-q}{j-1\choose q-1}=(-1)^{(j-1)-(q-1)}{j-2\choose q-2}-(-1)^{(j-1)-q}{j-2\choose q-1}
$$
而 $f_{i,j,l}$ 又有轉移 $f_{i,j,l}=f_{i-1,j,l}+f_{i-1,j-1,l-p_i}$ ,故:
$$
(-1)^{j-q}{j-1\choose q-1}f_{i,j,l}=(-1)^{j-q}{j-1\choose q-1}f_{i-1,j,l}+(-1)^{(j-1)-(q-1)}{j-2\choose q-2}f_{i-1,j-1,l-p_i}-(-1)^{(j-1)-q}{j-2\choose q-1}f_{i-1,j-1,l-p_i}
$$
發現了什麼?前面的係數只和 $j$ 與計算答案時所用的 $q$ 有關,所以設 $g_{i,j,l,t}$ 表示前 $i$ 種物質選出 $j$ 種,湊齊 $\sum p=l$ ,且最終計算時的 $q=t$ 的係數乘以方案數。則有:
$$
g_{i,j,l,t}=g_{i-1,j,l,t}+g_{i-1,j-1,l-p_i,t-1}-g_{i-1,j-1,l-p_i,t}
$$
咱們所作的彷佛都是無用功。但事實上,仔細觀察就會發現 $j$ 的一維已經沒有用處,不管是轉移仍是最終答案都不須要用到 $j$。

左右對 $j$ 那一維求和,便有 $h_{i,l,t}$ 表示前 $i$ 種物質選出若干種,湊齊 $\sum p=l$ ,且最終計算時的 $q=t$ 的係數乘以方案數,則有:
$$
h_{i,l,t}=h_{i-1,l,t}+h_{i-1,l-p_i,t-1}-h_{i-1,l-p_i,t}
$$
最終答案就是 $\sum\limits_{i=1}^mh_{n,i,q}\times \frac mi$ 。

時間複雜度 $O(nmq)$ ,因爲空間不足,須要使用滾動數組。

代碼

#include <cstdio>
#include <cstring>
#define mod 998244353
typedef long long ll;
ll p[1010] , f[2][10010][11];
inline ll qpow(ll x , ll y)
{
    ll ans = 1;
    while(y)
    {
        if(y & 1) ans = ans * x % mod;
        x = x * x % mod , y >>= 1;
    }
    return ans;
}
int main()
{
    int n , t , m , i , j , k , d;
    ll ans = 0;
    scanf("%d%d%d" , &n , &t , &m) , t = n - t + 1;
    for(i = 1 ; i <= n ; i ++ ) scanf("%lld" , &p[i]);
    for(i = 1 ; i <= t ; i ++ ) f[0][0][i] = -1;
    for(d = i = 1 ; i <= n ; i ++ , d ^= 1)
    {
        memcpy(f[d] , f[d ^ 1] , sizeof(f[d]));
        for(j = p[i] ; j <= m ; j ++ )
            for(k = 1 ; k <= t ; k ++ )
                f[d][j][k] = (f[d][j][k] + f[d ^ 1][j - p[i]][k - 1] - f[d ^ 1][j - p[i]][k] + mod) % mod;
    }
    for(i = 1 ; i <= m ; i ++ ) ans = (ans + f[n & 1][i][t] * m % mod * qpow(i , mod - 2)) % mod;
    printf("%lld\n" , ans);
    return 0;
}
相關文章
相關標籤/搜索