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


概念

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

例如:

\[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) \]

推導

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

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

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

\(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)\)

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

\(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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM