重返现世

III.重返现世

考虑扩展minmax定理:

\[\text{Kthmax}(\mathbb S)=\sum\limits_{\mathbb{T\subseteq S}}(-1)^{|\mathbb T|-K}\dbinom{|\mathbb T|-1}{K-1}\min(\mathbb T) \]

因为本题方便求的是 \(\min(\mathbb T)\),但是要求的却是 \(\text{Kthmin}\),所以我们不妨翻转 \(K\) 变成 \(\text{Kthmax}\)。并且,注意到有一行 \(n-k\leq10\),故翻转后亦有 \(K\leq10\)

现在,考虑 \(\min(\mathbb T)\) 应该怎么求。显然,其就是抽到任意 \(\mathbb T\) 中元素的期望时间,即 \(\dfrac m{\sum\limits_{i\in\mathbb T}a_i}\)

但是,明显我们不能枚举所有 \(\mathbb T\),因为 \(n\) 过大。但是,注意到 \(m\) 很小,故我们可以将 \(m\) 带进DP状态里。又因为那个不知道有啥用的 \(K\) 也很小,所以我们考虑将它也带进状态。

于是我们设计了这样的状态:\(f_{k,i,j}\) 表示 \(K=k\),当前考虑了前 \(i\) 个数,且 \(\sum\limits_{i\in\mathbb T}a_i=j\) 时,\(\sum\limits_{\mathbb{T\subseteq S}}(-1)^{|\mathbb T|-K}\dbinom{|\mathbb T|-1}{K-1}\) 之和。

现在,考虑 \(a_i\) 选还是不选。如果不选,显然有 \(f_{k,i,j}\leftarrow f_{k,i-1,j}\)

那如果选呢?我们考虑由 \(f_{k,i-1,j}\) 转移到 \(f_{k,i,j+a_i}\)。在前面的式子中,仅有 \(|\mathbb T|\) 一项产生了变化。\((-1)^{|\mathbb T|-K}\) 这项随着 \(|\mathbb T|\) 加一取反了,而 \(\dbinom{|\mathbb T|-1}{K-1}\) 这项呢?

依照二项式系数的递推公式,我们有 \(\dbinom{|\mathbb T|-1}{K-1}=\dbinom{|\mathbb T|-2}{K-1}+\dbinom{|\mathbb T|-2}{K-2}\)。这意味着,\(\sum\limits_{\mathbb{T\subseteq S}}(-1)^{|\mathbb T|-K}\dbinom{|\mathbb T|-1}{K-1}=-\sum\limits_{\mathbb{T\subseteq S}}(-1)^{|\mathbb T|-K}\dbinom{|\mathbb T|-2}{K-1}+\sum\limits_{\mathbb{T\subseteq S}}(-1)^{|\mathbb T|-K}\dbinom{|\mathbb T|-2}{K-2}\)(注意到仅有前面是个减号,因为 \(K-2\) 这项需要取两次反,等于没取,而前面这项取一次反),即 \(f_{k,i,j}\leftarrow f_{k-1,i-1,j-a_i}-f_{k,i-1,j-a_i}\)

明显是背包的样式,故 \(i\) 这维可以压掉。

关键是初始状态。事实上,\(f_{0,0,0}=0\),对于非零的 \(k\)\(f_{k,0,0}=-1\),这个奇奇怪怪的边界被证明是正确的。具体可以通过反推得出。

时间复杂度 \(O(nmk)\)

代码:

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
int ksm(int x,int y=mod-2){int z=1;for(;y;y>>=1,x=1ll*x*x%mod)if(y&1)z=1ll*z*x%mod;return z;}
int n,m,K,a[1010],f[11][10100],res;
int main(){
	scanf("%d%d%d",&n,&K,&m),K=n-K+1;
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int k=1;k<=K;k++)f[k][0]=mod-1;
	for(int i=1;i<=n;i++)for(int k=K;k;k--)for(int j=m;j>=a[i];j--)(f[k][j]+=(f[k-1][j-a[i]]-f[k][j-a[i]]+mod)%mod)%=mod;
	for(int i=1;i<=m;i++)(res+=1ll*f[K][i]*ksm(i)%mod)%=mod;
	printf("%d\n",1ll*res*m%mod);
	return 0;
}

posted @ 2021-04-09 14:19  Troverld  阅读(45)  评论(0编辑  收藏  举报