「ABC231 G」 Balls in Boxes 题解

「ABC231 G」 Balls in Boxes 题解

\(~~~~\) 终于有一道题让我有动力起魔怔标题了。

题意

\(~~~~\) \(n\) 个盒子,初始第 \(i\) 个盒子有 \(a_i\) 个球,将 \(k\) 个球依次独立随机放入 \(n\) 个盒子内。定义最终状态的权值为所有盒子内球数量的积,求期望权值。

\(~~~~\) \(1\leq n\leq 1000,1\leq k\leq 10^9\)

题解

\(~~~~\) 期望很假,由于放球共有 \(n^k\) 种情况这很好求,所以问题在于 \(n^k\) 种情况的权值和。

\(~~~~\) 假设所有 \(a_i=0\) 怎么做,记 \(x_{i,j}\in\{0,1\}\) 表示第 \(i\) 个盒子内是否放了球 \(j\),那贡献就可以表示为:

\[\large \prod_{i=1}^n (\sum_{j=1}^k x_{i,j}) \]

\(~~~~\) 展开的话就会是若干形似这样的项之和:

\[\large \prod_{i=1}^n x_{i,t_i}~~~~(t_i\in [1,n]) \]

\(~~~~\) 显然当所有 \(x\) 都取 \(1\) 时其才会产生贡献,更进一步这里取到的 \(t_i\) 应该互不相同。那合法的 \(\{t_i\}\) 就应该

\(~~~~\) 那考虑对于已经合法的 \(\{t_i\}\) ,其他球就可以乱放了,所以每组 \(\{t_i\}\) 对应 \(n^{k-n}\) 种方案,每种的贡献为 \(1\)

\(~~~~\) 所以最后的答案就是 \(\dfrac{k!}{(k-n)!}\times n^{k-n}\) ,然后除上总方案数就是期望。

\(~~~~\) 现在加上初始值,那我们认为每个盒子的增量\(b_i\) ,依然很好求总方案,那要求的最后的总权值期望是:

\[\large \sum_{\{b_i\}} (\prod_{i=1}^n(a_i+b_i)) \]

\(~~~~\) 把里面拆开可以发现总是由 \(x\)\(a\) 的积和 \(n-x\)\(b\) 的积做乘法,然后加和。

\(~~~~\) 那就预处理出所有由 \(x\)\(a\) 相乘得到的数之和 \(\text {and}\) 所有 \(n-x\)\(b\) 相乘的得到的数之和,其中 \(a\) 这部分记为 \(f\) ,可以有 DP:定义 \(f_{i,j}\) 表示前 \(i\) 个数中所有选 \(j\) 个情况的积的和,转移方程:\(f_{i,j}=f_{i-1,j}+f_{i-1,j-1}\times a_i\) 。而求 \(g\) 的话只需要类比上面就可以了,答案是 \(\dfrac{k!}{(k-i)!}\times n^{k-i}\)

\(~~~~\) 那最后的答案由 \(f\)\(g\) 卷一下就可以得到:

\[\large \sum_{i=0}^n f_i\times g_{n-i} \]

\(~~~~\) 然后再除以方案数就是期望了。

代码

查看代码
#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
const int MOD=998244353;
int n,k;
int arr[1005],dp[1005][1005],f[1005],g[1005];
ll qpow(ll a,ll b)
{
	ll ret=1;
	while(b)
	{
		if(b&1) ret=ret*a%MOD;
		b>>=1;a=a*a%MOD;
	}
	return ret;
}
int Get(int x)
{
	int ret=1;
	for(int i=k;i>=k-x+1;i--) ret=1ll*ret*i%MOD;
	return ret;
}
int main() {
	scanf("%d %d",&n,&k);
	dp[0][0]=1;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&arr[i]);
		for(int j=0;j<=n;j++)
			dp[i][j]=(dp[i-1][j]+(j>=1?1ll*dp[i-1][j-1]*arr[i]%MOD:0))%MOD;
		if(i==n) for(int j=0;j<=n;j++) f[j]=dp[i][j];
	}
	int Up=min(n,k);
	for(int i=0;i<=Up;i++) 
		g[i]=1ll*Get(i)*qpow(n,k-i)%MOD;
	int Ans=0;
	for(int i=0;i<=n;i++) Ans=(1ll*Ans+1ll*f[i]*g[n-i]%MOD)%MOD;
	printf("%lld",1ll*Ans*qpow(qpow(n,k),MOD-2)%MOD);
	return 0;
}
posted @ 2022-04-10 23:05  Azazеl  阅读(139)  评论(0)    收藏  举报