luoguP4707 重返现世(kthminmax容斥板题)
有\(n\)个不同的数,每秒有\(p_i\)的概率取出\(i\)。
问第一次出现第\(k\)个不同数的期望步数。
\(n\le 1000\),\(m\le 10000\),\(n-k\le 10\)
\(p_i\)表示为\(\frac{a_i}{m}\)的形式。
介绍个新姿势:kth-minmax容斥。
具体证明和普通的minmax容斥一样,同样考虑把\(S\)排序后,其中某个数\(S_i\)会算多少次。然后可以发现恰好只算到了\(S_{n-k+1}\)(注意是第\(k\)大)。
回到这题。首先\(k\leftarrow n-k+1\),即第\(k\)小变成第\(k\)大。
套式子。后面\(min\)的部分可以表示为\(\sum_{i\ge 0}(1-\sum_{j\in T}p_j)^i(\sum_{j\in T}p_j)(i+1)=\frac{1}{\sum_{j\in T}p_j}\)。
列出答案式子:\(\sum_{T}(-1)^{|T|-k}\binom{|T|-1}{k-1}\frac{1}{\sum_{j\in T}p_j}\),考虑把\(\sum_{j\in T}p_j\)相同的一起算,得到朴素的DP做法,记下当前搞到哪个数,\(|T|\)为多少,\(\sum_{j\in T}p_j\)为多少。
实际上可以发现:\((-1)^{|T|-k}\binom{|T|-1}{k-1}=(x-1)^{|T|-1}[x^{k-1}]\)。
于是改进DP:设\(f_{i,j}\),考虑前\(i\)个数,\(\sum_{j\in T}p_j\)为\(j\),存下一个多项式。转移的时候乘\((x-1)\)。
因为\(k\le 11\),时间是\(O(nm(n-k))\),能过。
细节:初值\(f_{0,0}=\frac{1}{x-1}\),不要忘了。
using namespace std;
#include <bits/stdc++.h>
#define N 1005
#define M 10005
#define K 13
#define ll long long
#define mo 998244353
ll qpow(ll x,ll y=mo-2){
ll r=1;
for (;y;y>>=1,x=x*x%mo)
if (y&1)
r=r*x%mo;
return r;
}
int n,k,m;
int p[N];
int C[N][N];
int f[M][K];
int main(){
// freopen("in.txt","r",stdin);
scanf("%d%d%d",&n,&k,&m);
k=n-k+1;
for (int i=1;i<=n;++i)
scanf("%d",&p[i]);
for (int i=0;i<=n;++i){
C[i][0]=1;
for (int j=1;j<=i;++j)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mo;
}
for (int i=0;i<k;++i)
f[0][i]=-1;
for (int i=0;i<n;++i)
for (int j=m-p[i+1];j>=0;--j){
(f[j+p[i+1]][0]-=f[j][0])%=mo;
for (int t=1;t<k;++t)
f[j+p[i+1]][t]=((ll)f[j+p[i+1]][t]-f[j][t]+f[j][t-1])%mo;
}
ll ans=0;
for (int j=1;j<=m;++j)
(ans+=qpow(j)*f[j][k-1])%=mo;
ans=(ans+mo)%mo*m%mo;
printf("%lld\n",ans);
return 0;
}