重返现世——Min-Max容斥+DP

题面

  洛谷P4707

解析

  先来证一下拓展$Min-Max$容斥:

  去证:$$kthmax(S) = sum_{T subseteq S}(-1)^{|T|-k}inom{|T|-1}{k-1}min(T)$$

  证明:

  构造容斥系数,设:$$kthmax(S) = sum_{T subseteq S}f(|T|)min(T)$$

  考虑$min(T)$为同一元素的系数之和,即$sum f(|T|)$。对于第$x+1$大的元素这个系数之和为$sum_{i=0}^xinom{x}{i}f(i+1)$,就是在比它大的$x$个数里选$i$个与它组成$T$集合。

  则有:$$[x==k-1]=sum_{i=0}^xinom{x}{i}f(i+1)$$

  二项式反演:$$f(x+1)=sum_{i=0}^x(-1)^{x-i}inom{x}{i}[i==k-1]$$$$f(x+1)=(-1)^{x-k+1}inom{x}{k-1}$$

  所以$$f(x)=(-1)^{x-k}inom{x-1}{k-1}$$

  故:$$egin{align*}kthmax(S) &= sum_{T subseteq S}f(|T|)min(T)\ &=sum_{T subseteq S}(-1)^{|T|-k}inom{|T|-1}{k-1}min(T)end{align*}$$

  得证


    题目要求第$K$小,其实就是$n+1-K$大

  因为$E(kthmax(S)) = sum_{T subseteq S}(-1)^{|T|-k}inom{|T|-1}{k-1}E(min(T))$

  $E(min(T))$表示第一次选中$T$内的数的期望时间,等于$frac{1}{sum_{i in T}frac{p_i}{m}}=frac{m}{sum_{iin T}p_i}$

  所以:$$egin{align*}E(kthmax(S)) &= sum_{T subseteq S}(-1)^{|T|-k}inom{|T|-1}{k-1}frac{m}{sum_{iin T}p_i}\ &= msum_{T subseteq S}frac{(-1)^{|T|-k}inom{|T|-1}{k-1}}{sum_{iin T}p_i}end{align*}$$

  但这道题$n leqslant 1000$,无法枚举子集,只能$DP$

  设集合$S_i=egin{Bmatrix}1,2,cdots,iend{Bmatrix}$,$f_{i,j,k}$表示考虑前$i$大的数,满足$sum p_x = j,xin T$的所有集合$T,Tsubseteq S_i$的$sum (-1)^{|T|-k}inom{|T|-1}{k-1}$值

  当$T$集合内不含$i$时,则:$f_{i,j,k}=f_{i-1,j,k}$

  当$T$集合内含$i$时,$$egin{align*}f_{i,j,k}&=sum_{iin T, T subseteq S_i} (-1)^{|T|-k}inom{|T|-1}{k-1}\ &=sum_{Tsubseteq S_{i-1}}(-1)^{|T|-k+1}inom {|T|}{k-1}\ &=sum_{Tsubseteq S_{i-1}}(-1)^{|T|-k+1}(inom{|T|-1}{k-2}+inom{|T|-1}{k-1})\ &=sum_{Tsubseteq S_{i-1}}(-1)^{|T|-k+1}inom{|T|-1}{k-2}+sum_{Tsubseteq S_{i-1}}(-1)^{|T|-k+1}inom{|T|-1}{k-1}\ &=sum_{Tsubseteq S_{i-1}}(-1)^{|T|-k+1}inom{|T|-1}{k-2}-sum_{Tsubseteq S_{i-1}}(-1)^{|T|-k}inom{|T|-1}{k-1}\ &= f_{i-1,j-p_i,k-1}-f_{i-1,j-p_i,k}end{align*}$$

  故:$f_{i,j,k}=f_{i-1,j,k}+f_{i-1,j-p_i,k-1}-f_{i-1,j-p_i,k}$

  边界:$f_{i,0,0}=1$

  时间复杂度:$O(nm|n-K|)$

 代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn = 1005, mod = 998244353;

ll qpow(ll x, ll y)
{
    ll ret = 1;
    while(y)
    {
        if(y&1)
            ret = ret * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return ret;
}

ll add(ll x, ll y)
{
    return x + y < mod? x + y: x + y - mod;
}

ll rdc(ll x, ll y)
{
    return x - y < 0? x - y + mod: x - y;
}

int n, m, K;
int a[maxn];
ll dp[2][maxn*10][12];

int main()
{
    scanf("%d%d%d", &n, &K, &m);
    K = n + 1 - K;
    for(int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    int pre, now;
    dp[0][0][0] = 1;
    for(int i = 1; i <= n; ++i)
    {
        now = (i & 1);
        pre = (now ^ 1);
        memset(dp[now], 0, sizeof(dp[now]));
        dp[now][0][0] = 1;
        for(int j = 0; j < a[i]; ++j)
            for(int k = 1; k <= K; ++k)
                dp[now][j][k] = dp[pre][j][k];
        for(int j = a[i]; j <= m; ++j)
            for(int k = 1; k <= K; ++k)
                dp[now][j][k] = add(dp[pre][j][k], rdc(dp[pre][j-a[i]][k-1], dp[pre][j-a[i]][k]));
    }
    ll ans = 0;
    for(int i = 1; i <= m; ++i)
        ans = add(ans, (dp[now][i][K] * qpow(i, mod - 2) % mod) * m % mod);
    printf("%lld", ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Joker-Yza/p/12398847.html