1. 程式人生 > 其它 >「ABC231 G」 Balls in Boxes 題解

「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;
}