CF1278F 解题报告

CF1278F 题解

题目链接

题目描述

\(m\) 张牌,其中一张为王牌。现执行以下操作 \(n\) 次:均匀随机洗牌后查看第一张牌是什么。

\(x\) 为洗牌后第一张牌为王牌的次数,求 \(x^k\) 的期望值。

题目分析

根据期望的定义可以得到答案就是概率和权值的乘积。

设 $ P = \frac{1}{m}$,考虑枚举出现的王牌的个数 \(x\) 则答案为

\[f(n,k) = \sum_{x=0}^n \binom{n}{x} P^x (1-P)^{n-x} x^k \]

直接计算的话是 \(O(n)\) 的,考虑用 \(k\) 进行递推。

\[f(n,k+1) = \sum_{x=0}^n \binom{n}{x} P^x (1-P)^{n-x} x^{k+1} \]

展开组合数 \(\binom{n}{x}\) 可得

\[f(n,k+1) = \sum_{x=0}^n \frac{n !}{x! (n-x)!} P^x (1-P)^{n-x} x^{k+1} \]

\(x^{k+1}\) 取出 \(x\) 可得

\[f(n,k+1) = \sum_{x=0}^n \frac{n !}{(x-1)! (n-x)!} P^x (1-P)^{n-x} x^k \]

\(n!\) 中取出 \(n\),从 \(P^x\) 中取出一个 \(P\) 可得

\[f(n,k+1) = \sum_{x=0}^n \frac{(n-1) !}{(x-1)! (n-x)!} P^{x-1} (1-P)^{n-x} x^k \times P\times n \]

因为 \(x=0\) 时不会对答案造成贡献所以 \(x-1\) 的取值为 \([0,n-1]\),考虑枚举 \(x-1\) 来代替 \(x\) 可得

\[f(n,k+1) = \sum_{x=0}^{n-1} \frac{(n-1) !}{x! (n-x-1)!} P^x (1-P)^{n-x-1} (x+1)^k \times P\times n \]

用二项式定理拆解 \((x+1)^k\) 可得

\[f(n,k+1) =n \times P \times \sum_{x=0}^{n-1} \frac{(n-1) !}{x! (n-x-1)!} P^x (1-P)^{n-x-1} \sum_{i=0}^k \binom{k}{i}x^i \]

更改求和顺序可得

\[f(n,k+1) =n \times P \times \sum_{i=0}^k \binom{k}{i} \sum_{x=0}^{n-1} \frac{(n-1) !}{x! (n-x-1)!} P^x (1-P)^{n-x-1}x^i \]

观察式子后半段,发现即为 \(f(n-1,i)\),由此可得

\[f(n,k+1) =n \times P \times \sum_{i=0}^k \binom{k}{i}f(n-1,i) \]

由此我们得到了一个 \(O(k^3)\) 的记忆化搜索做法。终止状态为 \(f(x,0)=1\)

继续优化,考虑每个 \(f(x,0)\) 对答案的贡献,贡献式即为

\[f(n,k)=\sum \binom{k-1}{x_1}\times n\times P\times \binom{x_1-1}{x_2} \times (n-1) \times P \times \dots \times f(x,0) \]

我们发现 \(n \times P \times (n-1) \times P \times \dots \times (x+1) \times P\) 只与 \(x\) 相关,这启发我们枚举 \(x\) 并计算答案。

我们记 \(g(x)=n \times P \times (n-1) \times P \times \dots \times (x+1) \times P\)\(f(x,0)\) 对答案的贡献为

\[f(n,k)=\sum g(x) f(x,0) \prod_{i=0}^{n-x-1} \binom{x_i-1}{x_{i+1}} \]

其中 \(x_0=k\) 并且 \(x_{n-x}\)\(0\)

考虑后面式子的组合意义就是从 \(k\) 个石子中钦定编号最小的不选择,选择剩下的部分任意多个石子,然后递归进行子问题。

考虑动态规划解决问题,设 \(dp(i,j)\) 表示考虑前 \(i\) 个数,现在在第 \(j\) 层子问题的递归中的答案。初始状态 \(dp(0,0)=1\)

考虑两种不同转移。

第一种不进行递归,则 \(i+1\) 号石子可能属于 \(j\) 层中的任意一层。

第二种递归下一层,因为需要钦定编号最小的石子一定不能递归,所以 \(i+1\) 号石子一定只能属于 \(j+1\) 层。

时间复杂度为 \(O(k^2)\)

代码实现

动态规划部分使用的不是题解部分的填表法,而是刷表法。为了保险,分了两个部分,\(n>k\)\(n \le k\)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
template<typename T>inline void read(T &x)
{
	x=0;T f=1;char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^48);
	x*=f;
}
template<typename T,typename ...Arg>inline void read(T &x,Arg &...arg){read(x);read(arg...);}
template<typename T>inline void print(T x)
{
	if(x<0) putchar('-'),x=-x;
	if(x>9) print(x/10);
	putchar((x%10)^48);
}
template<typename T>inline void print(T x,char c){print(x);putchar(c);}
template<typename T>inline void output(T x){print(x,' ');}
template<typename T,typename ...Arg>inline void output(T x,Arg ...arg){output(x);output(arg...);}
const int N=5007,mod=998244353;
int n,m,k,P,Q,PX[N],PP[N],PQ[N],fct[N],inv[N],ans,ddd[5007][5007];
int fpow(int x,int y)
{
	int res=1;
	while(y)
	{
		if(y&1) res=(ll)res*x%mod;
		x=(ll)x*x%mod; y>>=1;
	}
	return res;
}
int __C(int x,int y){return (ll)fct[x]*inv[y]%mod*inv[x-y]%mod;}
void prework()
{
	fct[0]=PP[0]=PQ[0]=1;
	for(int i=1;i<=k;i++)
		PX[i]=fpow(i,k),fct[i]=(ll)fct[i-1]*i%mod,
		PP[i]=(ll)PP[i-1]*P%mod,PQ[i]=(ll)PQ[i-1]*Q%mod;
	inv[k]=fpow(fct[k],mod-2);
	for(int i=k;i>=1;i--)
		inv[i-1]=(ll)inv[i]*i%mod;
}
void solve1()
{
	ans=0;
	for(int x=1;x<=n;x++)
		ans=(ans+(ll)__C(n,x)*PX[x]%mod*PP[x]%mod*PQ[n-x]%mod)%mod;
	print(ans,'\n');
}
void solve2()
{
	ddd[0][0]=1;
	for(int i=0;i<k;i++)
		for(int j=0;j<=k;j++)
			ddd[i+1][j]=(ddd[i+1][j]+(ll)ddd[i][j]*j%mod)%mod,
			ddd[i+1][j+1]=(ddd[i+1][j+1]+ddd[i][j])%mod;
	
	int tot=1; ans=0;
	for(int i=1;i<=k;i++)
		tot=(ll)tot*P%mod*(n-i+1)%mod,
		ans=(ans+(ll)ddd[k][i]*tot%mod)%mod;
	print(ans,'\n');
}
int main()
{
	read(n,m,k); P=fpow(m,mod-2),Q=(1+mod-P)%mod;
	prework();
	if(n<=k) solve1();
	else solve2();
	return 0;
}
posted @ 2023-02-25 09:13  slenbol  阅读(58)  评论(0)    收藏  举报