题面
解析
先来证一下拓展$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|)$
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }