P4707-重返现世【dp,数学期望,扩展min-max容斥】
正题
题目链接:https://www.luogu.com.cn/problem/P4707
题目大意
\(n\)个物品,每次生成一种物品,第\(i\)个被生成的概率是\(\frac{p_i}{m}\),求生成至少\(k\)种物品的期望次数。
\(1\leq n\leq 1000,max\{n-10,1\}\leq k\leq n,1\leq m\leq 10000\)
解题思路
求的是\(E(min_k\{S\})\),但是\(k\)很大,如果令\(k=n-k+1\)的话就是求\(E(max_k\{S\})\)了
然后就可以用\(min-max\)容斥的扩展了
\[max_k(S)=\sum_{T\in S}(-1)^{|T|-k}\binom{|T|-1}{k-1}min(T)
\]
然后\(min\)的话挺好搞的,因为这个集合中的所有物品都可以视为一个物品,所以期望就是\(\frac{m}{\sum_{i\in T}p_i}\)
然后因为显然不能暴力枚举集合,所以我们考虑\(dp\)。设\(f_{k,i,j}\)表示做到第\(k\)个物品,目前的\(\sum_{i\in T}p_i=m\),然后上面那个式子的\('k'\)的值是\(j\)时上面那个式子的和。
因为有个组合数转移起来挺麻烦的,不选的话就是\(f_{k-1,i,j}\)不再多说,但是如果选的话,那个\((-1)^{|T|-k}\)直接取反就好了,但是那个组合数的上那个也加了\(1\)。
这里我们直接用那个组合数的式子\(\binom{n}{m}=\binom{n-1}{m-1}+\binom{n-1}{m}\)。虽然上面那个式子的\(k\)是不变的,但是我们记录了其他的\(k\)的值,其实如果选的话转移就是
\[f_{k,i,j}=f_{k-1,i,j}+f_{k-1,i-p_k,j-1}-f_{k-1,i-p_{k},j}
\]
这样我们的式子就是\(O(nmk)\)的了。
然后初始化的话为了满足后面的定义,让所有的\(f_{0,0,i}=-1(i\in[1,m])\)就好了。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int P=998244353;
int n,k,m,f[11000][11],ans;
int power(int x,int b){
int ans=1;
while(b){
if(b&1)ans=1ll*ans*x%P;
x=1ll*x*x%P;b>>=1;
}
return ans;
}
int main()
{
scanf("%d%d%d",&n,&k,&m);k=n-k+1;
for(int p=1;p<=k;p++)f[0][p]=-1;
for(int p=1;p<=n;p++){
int x;scanf("%d",&x);
for(int i=m;i>=x;i--)
for(int j=k;j>=1;j--)
(f[i][j]+=(f[i-x][j-1]-f[i-x][j]+P)%P)%=P;
}
for(int p=1;p<=m;p++)
(ans+=1ll*f[p][k]*power(p,P-2)%P)%=P;
printf("%d\n",1ll*ans*m%P);
return 0;
}