【洛谷P4707】重返现世【扩展Min-Max容斥】【dp】

传送门

题意: N N N种物品,每次第 i i i种产生概率为 p i M \frac{p_i}{M} Mpi, ∑ p i = M \sum p_i=M pi=M。求生成 K K K种不同物品的期望时间 模 998244353 998244353 998244353

N ≤ 1000 , M ≤ 10000 , N − K ≤ 10 N \leq1000,M \leq 10000,N-K\leq10 N1000,M10000,NK10

又是神仙题……

套路性地把每个物品出现的时间丢到一个集合 S S S里面,我们要求的是集合第 N − K + 1 N-K+1 NK+1

而最小是随便求的

所以魔改一下Min-Max容斥

假设存在 f ( x ) f(x) f(x)满足

max ⁡ k ( S ) = ∑ T ⊆ S f ( ∣ T ∣ ) min ⁡ ( T ) \max_k(S)=\sum_{T \subseteq S}f(|T|)\min(T) kmax(S)=TSf(T)min(T)

考虑第 m + 1 m+1 m+1大的数产生的贡献

∑ i = 0 m C m i f ( i + 1 ) \sum_{i=0}^m C_m^if(i+1) i=0mCmif(i+1)

我们希望第 k k k大的数贡献一次 即

[ m = k − 1 ] = ∑ i = 0 m C m i f ( i + 1 ) [m=k-1]=\sum_{i=0}^m C_m^if(i+1) [m=k1]=i=0mCmif(i+1)

二项式反演一波

F ( m ) = [ m = k − 1 ] , G ( i ) = f ( i + 1 ) F(m)=[m=k-1],G(i)=f(i+1) F(m)=[m=k1],G(i)=f(i+1)

F ( m ) = ∑ i = 0 m C m i G ( i ) F(m)=\sum_{i=0}^mC_m^iG(i) F(m)=i=0mCmiG(i)

G ( m ) = ∑ i = 0 m ( − 1 ) m − i C m i F ( i ) G(m)=\sum_{i=0}^m(-1)^{m-i}C_m^iF(i) G(m)=i=0m(1)miCmiF(i)

f ( m + 1 ) = ( − 1 ) m − k + 1 C m k − 1 f(m+1)=(-1)^{m-k+1}C_m^{k-1} f(m+1)=(1)mk+1Cmk1

f ( m ) = ( − 1 ) m − k C m − 1 k − 1 f(m)=(-1)^{m-k}C_{m-1}^{k-1} f(m)=(1)mkCm1k1

所以

max ⁡ k ( S ) = ∑ T ⊆ S ( − 1 ) ∣ T ∣ − k C ∣ T ∣ − 1 k − 1 min ⁡ ( T ) \max_k(S)=\sum_{T \subseteq S}(-1)^{|T|-k}C_{|T|-1}^{k-1}\min(T) kmax(S)=TS(1)TkCT1k1min(T)

当然是期望下的

子集最小可以随便求,所以考虑前面那坨怎么搞

考虑dp

定义状态 d p ( i , j , k ) dp(i,j,k) dp(i,j,k)表示从前 i i i个物品选出 p p p的和为 j j j作为 T T T ( − 1 ) ∣ T ∣ − k C ∣ T ∣ − 1 k − 1 (-1)^{|T|-k}C_{|T|-1}^{k-1} (1)TkCT1k1的和

考虑转移

不选当前点 即 d p ( i − 1 , j , k ) dp(i-1,j,k) dp(i1,j,k)

选当前点 即

∑ i ∈ T ( − 1 ) ∣ T ∣ − k C ∣ T ∣ − 1 k − 1 \sum_{i\in T}(-1)^{|T|-k}C_{|T|-1}^{k-1} iT(1)TkCT1k1

i i i丢掉

∑ T ( − 1 ) ∣ T ∣ − k + 1 C ∣ T ∣ k − 1 \sum_T(-1)^{|T|-k+1}C_{|T|}^{k-1} T(1)Tk+1CTk1

注意此时的 T T T在前 i − 1 i-1 i1个中选

由于前后的 T T T不统一,无法转移,所以……拆组合数

∑ T ( − 1 ) ∣ T ∣ − k + 1 C ∣ T ∣ − 1 k − 1 + ∑ T ( − 1 ) ∣ T ∣ − k + 1 C ∣ T ∣ − 1 k − 2 \sum_T(-1)^{|T|-k+1}C_{|T|-1}^{k-1}+\sum_T(-1)^{|T|-k+1}C_{|T|-1}^{k-2} T(1)Tk+1CT1k1+T(1)Tk+1CT1k2

− ∑ T ( − 1 ) ∣ T ∣ − k C ∣ T ∣ − 1 k − 1 + ∑ T ( − 1 ) ∣ T ∣ − k + 1 C ∣ T ∣ − 1 k − 2 -\sum_T(-1)^{|T|-k}C_{|T|-1}^{k-1}+\sum_T(-1)^{|T|-k+1}C_{|T|-1}^{k-2} T(1)TkCT1k1+T(1)Tk+1CT1k2

再次强调是前 i − 1 i-1 i1个中选的

所以就是

d p ( i , j , k ) = d p ( i − 1 , j , k ) + d p ( i − 1 , j − p i , k − 1 ) − d p ( i − 1 , j − p i , k ) dp(i,j,k)=dp(i-1,j,k)+dp(i-1,j-p_i,k-1)-dp(i-1,j-p_i,k) dp(i,j,k)=dp(i1,j,k)+dp(i1,jpi,k1)dp(i1,jpi,k)

然而还有个让人头大的边界问题

j < p i j<p_i j<pi也就是不能选当前点 d p ( i , j , k ) = d p ( i − 1 , j , k ) dp(i,j,k)=dp(i-1,j,k) dp(i,j,k)=dp(i1,j,k)

j = p i j=p_i j=pi

如果要选就是从空集转移过来,但空集代进去超过了人类的认知,所以直接用定义算

显然就是 ∣ T ∣ = 1 |T|=1 T=1

( − 1 ) 1 − k C 0 k − 1 = [ k = 1 ] (-1)^{1-k}C_0^{k-1}=[k=1] (1)1kC0k1=[k=1]

所以 d p ( i , j , k ) = d p ( i − 1 , j , k ) + [ k = 1 ] dp(i,j,k)=dp(i-1,j,k)+[k=1] dp(i,j,k)=dp(i1,j,k)+[k=1]

j > p i j>p_i j>pi正常转移

滚动数组优化一下即可

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
using namespace std;
const int MOD=998244353;
typedef long long ll;
int p[1005],dp[2][10005][15];
inline int qpow(int a,int p)
{
	int ans=1;
	while (p)
	{
		if (p&1) ans=(ll)ans*a%MOD;
		a=(ll)a*a%MOD;p>>=1;
	}
	return ans;
}
#define inv(x) qpow(x,MOD-2)
int main()
{
	int N,K,M;
	scanf("%d%d%d",&N,&K,&M);
	K=N-K+1;
	for (int i=1;i<=N;i++) scanf("%d",&p[i]);
	int cur=1;
	for (int i=1;i<=N;i++)
	{
		for (int j=0;j<p[i];j++)
			for (int k=1;k<=K;k++)
				dp[cur][j][k]=dp[cur^1][j][k];
		for (int k=1;k<=K;k++) dp[cur][p[i]][k]=dp[cur^1][p[i]][k]+(k==1);
		for (int j=p[i]+1;j<=M;j++)
			for (int k=1;k<=K;k++)
				dp[cur][j][k]=((ll)dp[cur^1][j][k]+dp[cur^1][j-p[i]][k-1]-dp[cur^1][j-p[i]][k]+MOD)%MOD;
		cur^=1;
	}
	int ans=0;
	for (int i=1;i<=M;i++) ans=(ans+(ll)dp[N&1][i][K]*M%MOD*inv(i)%MOD)%MOD;
	printf("%d",(ans+MOD)%MOD);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值