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

题面

  洛谷P4707

解析

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

  去证:$$kthmax(S) = \sum_{T \subseteq S}(-1)^{|T|-k}\binom{|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}^x\binom{x}{i}f(i+1)$,就是在比它大的$x$个数里选$i$个与它组成$T$集合。

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

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

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

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

  得证


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

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

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

  所以:$$\begin{align*}E(kthmax(S)) &= \sum_{T \subseteq S}(-1)^{|T|-k}\binom{|T|-1}{k-1}\frac{m}{\sum_{i\in T}p_i}\\ &= m\sum_{T \subseteq S}\frac{(-1)^{|T|-k}\binom{|T|-1}{k-1}}{\sum_{i\in T}p_i}\end{align*}$$

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

  设集合$S_i=\begin{Bmatrix}1,2,\cdots,i\end{Bmatrix}$,$f_{i,j,k}$表示考虑前$i$大的数,满足$\sum p_x = j,x\in T$的所有集合$T,T\subseteq S_i$的$\sum (-1)^{|T|-k}\binom{|T|-1}{k-1}$值

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

  当$T$集合内含$i$时,$$\begin{align*}f_{i,j,k}&=\sum_{i\in T, T \subseteq S_i} (-1)^{|T|-k}\binom{|T|-1}{k-1}\\ &=\sum_{T\subseteq S_{i-1}}(-1)^{|T|-k+1}\binom {|T|}{k-1}\\ &=\sum_{T\subseteq S_{i-1}}(-1)^{|T|-k+1}(\binom{|T|-1}{k-2}+\binom{|T|-1}{k-1})\\ &=\sum_{T\subseteq S_{i-1}}(-1)^{|T|-k+1}\binom{|T|-1}{k-2}+\sum_{T\subseteq S_{i-1}}(-1)^{|T|-k+1}\binom{|T|-1}{k-1}\\ &=\sum_{T\subseteq S_{i-1}}(-1)^{|T|-k+1}\binom{|T|-1}{k-2}-\sum_{T\subseteq S_{i-1}}(-1)^{|T|-k}\binom{|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

猜你喜欢

转载自www.cnblogs.com/Joker-Yza/p/12398847.html
今日推荐