[Luogu#4707] 重返现世(min-max容斥+背包dp)

Posted cyf32768

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Luogu#4707] 重返现世(min-max容斥+背包dp)相关的知识,希望对你有一定的参考价值。

Address

Luogu#4707

Solution

前置技能:记 (max_k(S)) 表示 (S) 中第 (k) 大的数,(min(S)) 表示 (S) 中最小的数,那么有:[max_k(S)=sum_{T∈S,T eqemptyset}inom{|T|-1}{k-1}(-1)^{|T|-k}min(T)]证明:我们考虑构造容斥系数,即设:
[max_k(S)=sum_{T∈S,T eqemptyset}f(|T|)min(T)](min(T)=min_x(S)) 时:
[sum f(|T|)=sum_{i=0}^{n-x}inom{n-x}{i}f(i+1)]那么有:[sum_{i=0}^{n-x}inom{n-x}{i}f(i+1)=[x=n-k+1]=[n-x=k-1]]二项式反演可得:
[f(a+1)=sum_{i=0}^ainom{a}{i}(-1)^{a-i}[i=k-1]] 因此:
[f(a)=inom{a-1}{k-1}(-1)^{a-k}]即:
[f(|T|)=inom{|T|-1}{k-1}(-1)^{|T|-k}] ( ext{min-max}) 容斥可以扩展到期望上来,即 [E(max_k(S))=sum_{T∈S,T eqemptyset}inom{|T|-1}{k-1}(-1)^{|T|-k}E(min(T))] 接下来考虑对于一个集合 (T),怎样计算 (E(min(T)))

(P(T)=sum_{i∈T}p_i),那么把 (T) 集合内的物品看作一个整体,其它物品也看作一个整体。问题转化为:有两个物品,每次取到 (1) 号的概率为 (frac{P(T)}{m}),取到 (2) 号的概率为 (1-frac{P(T)}{m}),问取到 (1) 号的期望次数。

设取到 (1) 号的期望次数为 (x),则 (x=frac{P(T)}{m}+(1-frac{P(T)}{m})(x+1)),解得 (x=frac{m}{P(T)})

注意题目中的 (k) 指的是 (min_k(S)),令 (k=n-k+1),变为求 (E(max_k(S)))

如果对于每个 (P(T)=j) 的集合 (T),算出它们的 (inom{|T|-1}{k-1}(-1)^{|T|-k}) 之和,就能求出答案了。

考虑 ( ext{dp}),记 (f[i][j][k]) 表示考虑前 (i) 个数的子集 (T)(P(T)=j),它们的 (inom{|T|-1}{k-1}(-1)^{|T|-k}) 之和,初值 (f[0][0][0]=1)

转移:

  1. (T) 中没有 (i),那么 (f[i][j][k]+=f[i-1][j][k])
  2. (T) 中有 (i),那么我们先把 (T) 中的 (i) 移除,然后 (T) 变成了前 (i-1) 个数的子集:[sum_{T}inom{|T|}{k-1}(-1)^{|T|+1-k}] [=sum_T[inom{|T|-1}{k-1}+inom{|T|-1}{k-2}](-1)^{T-k+1}] [=sum_Tinom{|T|-1}{k-1}(-1)^{T-k}(-1)+sum_Tinom{|T|-1}{(k-1)-1}(-1)^{|T|-(k-1)}] [=f[i-1][j-p_i][k-1]-f[i-1][j-p_i][k]]

综上所述,(f[i][j][k]=f[i-1][j][k]+(f[i-1][j-p_i][k-1]-f[i-1][j-p_i][k])[kgeq 1])

时间复杂度 (O(n(n-k)m)),注意第一维要滚动。

Code

#include <bits/stdc++.h>

using namespace std;

#define ll long long

template <class t>
inline void read(t & res)
{
    char ch;
    while (ch = getchar(), !isdigit(ch));
    res = ch ^ 48;
    while (ch = getchar(), isdigit(ch))
    res = res * 10 + (ch ^ 48);
}

const int e = 10005, mod = 998244353;
int p[e], f[2][e][15], inv[e], n, q, m, ans;

inline void add(int &x, int y)
{
    (x += y) >= mod && (x -= mod);
}

int main()
{
    int i, j, k, s = 0;
    read(n); read(q); read(m); q = n - q + 1;
    f[0][0][0] = 1; inv[1] = 1;
    for (i = 2; i <= m; i++) inv[i] = (ll)(mod - mod / i) * inv[mod % i] % mod;
    for (i = 1; i <= n; i++) read(p[i]);
    for (i = 1; i <= n; i++)
    {
        int nxt = i & 1, lst = nxt ^ 1;
        memset(f[nxt], 0, sizeof(f[nxt]));
        s += p[i];
        for (j = 0; j <= s; j++)
        for (k = 0; k <= q; k++)
        {
            f[nxt][j][k] = f[lst][j][k];
            if (j >= p[i] && k) 
            {
                add(f[nxt][j][k], f[lst][j - p[i]][k - 1]);
                add(f[nxt][j][k], mod - f[lst][j - p[i]][k]);
            }
        }
    }
    for (i = 1; i <= m; i++) ans = (ans + (ll)f[n & 1][i][q] * inv[i]) % mod;
    ans = (ll)ans * m % mod;
    cout << ans << endl;
    return 0;
}

以上是关于[Luogu#4707] 重返现世(min-max容斥+背包dp)的主要内容,如果未能解决你的问题,请参考以下文章

偶的题

「Luogu4321」随机游走

luogu P3175 [HAOI2015]按位或

HDOJ 4707(模板)

hdu 4707 Pet

hdoj 4707 BFS