其他分享
首页 > 其他分享> > 重返现世

重返现世

作者:互联网

重返现世

min-max 容斥,DP

记 \(\min\limits_k\{S\}\) 表示 \(S\) 中出现至少 \(k\) 个元素的期望时间

答案便为 \(\min\limits_{k} \{U\}, U = \{n \cdot 1\}\)

考虑到 \(k\) 很大,而 \(n - k\) 很小,所以转化一下

\(\min\limits_k \{U\} = \max\limits_{n - k + 1} \{U\}\)

记 \(k' = n - k + 1\) 再根据扩展 min-max 容斥,得

\(\max\limits_{k'} \{S\} = \sum\limits_{T \subseteq S} (-1) ^ {|T| - k'} \begin{pmatrix}|T| - 1\\k'- 1\end{pmatrix} \min\{T\}\)

还是根据几何分布,有 \(\min\{T\} = \frac m {\sum_{i\in S} p_i}\)

但这样直接做的时间复杂度是 \(O(2^n)\) 的,考虑换种做法

设 \(f_{i, j,k}\) 表示前 \(i\) 个数中的一些数组成集合 \(S\) ,\(\sum_{i \in S} p_i = j\) 时,\(\sum\limits_{T\subseteq S} (-1)^{|T| - k}\begin{pmatrix}|T| - 1\\k - 1\end{pmatrix}\) 的值

考虑第 \(i\) 个数选不选

综上,\(f_{i,j, k} = f_{i - 1, j, k} + f_{i - 1,j - p_i, k - 1} - f_{i - 1, j - p_i, k}\)

当 \(i = 0, j = 0, k = 0\) 时,带入定义式有 \(f_{0, 0, 0} = 0\)

时间复杂度:\(O(n m (n - k + 1))\) ,滚动数组优化后空间复杂度:\(O(m(n - m + 1))\)

#include <bits/stdc++.h>
#define re register
#define int long long
// #define pair pair<int, int>
// #define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout);
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 21], *p1 = buf, *p2 = buf;
using namespace std;
inline int read()
{
    re int x = 0, f = 0;
    re char ch = getchar();
    while (!isdigit(ch)) {if (ch == '-') f = 1; ch = getchar();}
    while (isdigit(ch)) {x = (x << 3) + (x << 1) + ch - 48; ch = getchar();}
    return f ? -x : x;
}
inline string getstr()
{
    string res = "";
    re char ch = getchar();
    while (isspace(ch)) ch = getchar();
    while (!isspace(ch)) res.push_back(ch), ch = getchar();
    return res;
}
const int N = 1e3 + 3, P = 998244353, M = 1e4 + 4;
int n, K, m;
int p[N], f[2][M][12], inv[M];
signed main()
{
    n = read(), K = n + 1 - read(), m = read();
    inv[1] = 1;
    for (re int i = 2; i <= m; ++i) inv[i] = P - P / i * inv[P % i] % P;
    for (re int i = 1; i <= n; ++i) p[i] = read();
    re bool flag = 1;
    for (re int i = 1; i <= n; ++i, flag ^= 1)
    {
        for (re int j = 1; j <= m; ++j)
        {
            for (re int k = 1; k <= K; ++k)
            {
                f[flag][j][k] = f[flag ^ 1][j][k];
                if (j < p[i]) continue;
                if (j == p[i] && k == 1) f[flag][j][k]++;
                else
                {
                    f[flag][j][k] = (f[flag][j][k] + f[flag ^ 1][j - p[i]][k - 1] - f[flag ^ 1][j - p[i]][k]) % P;
                    if (f[flag][j][k] < 0) f[flag][j][k] += P;    
                }
            }
        }
    }
    flag ^= 1;
    int ans = 0;
    for (re int i = 1; i <= m; ++i) ans = (ans + f[flag][i][K] * m % P * inv[i] % P) % P;
    printf("%lld", ans);
    return 0;
}

标签:begin,end,limits,min,sum,重返,pmatrix,现世
来源: https://www.cnblogs.com/After-glow/p/15836751.html