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;
}
posted @ 2021-03-27 08:07  QuantAsk  阅读(72)  评论(0编辑  收藏  举报