[CF850F] Rainbow Balls 题解

[CF850F] Rainbow Balls 题解


题意分析

在一个袋子中,有 \(n\) 种颜色的球,每种颜色分别有 \(a_i\) 种。

接下来,每次操作中取两个不一样的球(颜色可以相同),将其中一个涂成另一个的颜色。

问:使所有球都变成一种颜色的操作次数的期望值为多少?

以有理数 \(\frac{P}{Q}\)\(M = 10^9 + 7\) 的形式输出(其中 \(\gcd{(P,Q)} = 1\)),也就是 \(P \cdot Q^{-1} \pmod{M}\)

这明显是一道期望 DP。


思路分析

状态定义

那我们该如何求解这一道期望 DP 呢?

从数据范围入手,\(1 \le n \le 2.5\times 10^3\),而 \(1 \le a_i \le 10^5,\forall i \in [1,n]\),那么我们可以联想到:

这应该是一道与 \(a_i\) 的数据范围有关的题目,需要 \(O(n\log{M})\) 或优于 \(O(n\log{M})\) 的做法,那么 DP 应该是线性的,对于 DP 数组,也应是形如 \(\{ f_i \}\) 的一维数组。

那么我们可以通过期望的离散型定义来看:

设离散型随机变量 \(X\) 的分布律为 $P_{ X = x_k } = p_k,k \in N^* $,若级数 \(\sum_{k=1}^{\infty} |x_k| \cdot p_k < +\infty\),记 \(E_X = \sum_{k=1}^{\infty} x_k \cdot p_k\)。则称 \(E_X\) 为随机变量 \(X\) 的数学期望。

其中,\(E_X = \sum_{k=1}^{\infty} x_k \cdot p_k\),我们从这里切入。

我们可以把它分解成对于每个颜色的子问题,再把它加起来,那么状态可以为:

\(E_i\) 表示总共有 \(i\) 个相同颜色的小球,把所有球都变成该颜色的期望次数;

\(P_i\) 表示总共有 \(i\) 个相同颜色的小球,把所有球都变成该颜色的概率。

所以式子应改为 \(E = \sum_{i=1}^{n} E_{a_i} \cdot P_{a_i}\)

求解公式

对于 \(\{ P_i \}\)

初始状态为 \(P_0 = 0 , P_{sum} = 1\)(其中 \(sum=\sum_{i=1}^{n}a_i\),下同)。

假设现在有 \(x\) 个某颜色的球,那么总共选择方案有 \((sum-1)sum\) 种,变为 \(x-1\) 个的方案有 \(x(sum-x)\) 种,变为 \(x+1\) 个的方案也是有 \(x(sum-x)\) 种,因此从 \(x\) 变为 \(x-1\) 个与变为 \(x+1\) 个的概率相同,故得到式子:

\[\begin{aligned} P_x & = \frac{P_{x+1}+P_{x-1}}{2}\\ P_{x+1} - P_x & = P_x - P_{x-1}\\ \end{aligned} \]

因此 \(\{ P_i \}\) 是一个等差数列,通项公式为 \(P_i = \frac{i}{sum}\)

对于 \(\{ E_i \}\)

仍设现在有 \(x\) 个某颜色的球,那么总共选择方案有 \((sum-1)sum\) 种,变为 \(x-1\) 个的方案有 \(x(sum-x)\) 种,变为 \(x+1\) 个的方案也是有 \(x(sum-x)\) 种,那么操作后 \(x\) 会变化的概率是 \(p = \frac{2x(sum-x)}{sum(sum-1)}\),因此操作后 \(x\) 会变化的期望步数是 \(\frac{1}{p} = \frac{sum(sum-1)}{2x(sum-x)}\)(概率学知识,我不太懂)。

那么得到式子:

\[\begin{aligned} E_i & = \frac{P_{i-1}E_{i-1} + P_{i+1}E_{i+1}}{P_{i-1}+P_{i+1}} + \frac{sum(sum-1)}{2i(sum-i)} \\ E_i & = \frac{(i-1)E_{i-1} + (i+1)E_{i+1}}{2i} + \frac{sum(sum-1)}{2i(sum-i)} \\ \end{aligned} \]

状态化简

我们求出 \(\{ P_i \}\)\(\{ E_i \}\) 后,发现似乎不是很好求解,那么我们回到原式子:\(E = \sum_{i=1}^{n} E_{a_i} \cdot P_{a_i}\)

经过我们的结果,此时式子可以化为:\(E = \sum_{i=1}^{n} \frac{a_iE_{a_i}}{sum}\)

那么我们直接定义 \(f_i = \frac{iE_{i}}{sum}\),进行转移。

它的初始状态也很容易得到:\(f_0 = 0,f_{sum} = 0\)(虽然 \(f_0\) 无意义,但有几率会变为这个状态,同时也为了方便,在此设为 \(0\))。

我们继续推导:

\[\begin{aligned} E_i & = \frac{(i-1)E_{i-1} + (i+1)E_{i+1}}{2i} + \frac{sum(sum-1)}{2i(sum-i)} \\ \frac{sumf_i}{i} & = \frac{sumf_{i-1} + sumf_{i+1}}{2i} + \frac{sum(sum-1)}{2i(sum-i)} \\ 2f_i & = f_{i-1} + f_{i+1} + \frac{sum-1}{sum-i} \\ f_{i+1} & = 2f_i - f_{i-1} - \frac{sum-1}{sum-i} \\ f_{i} & = 2f_{i-1} - f_{i-2} - \frac{sum-1}{sum-i+1} \\ \end{aligned} \]

这很明显可以用数学归纳法求解。

归纳法求解

在此我们直接求出 \(f_1\) 的值,然后就可以递推求解。

\(x=sum-1\) 代入式子中可得:

\[\begin{aligned} f_{sum} & = 2f_{sum-1} - f_{sum-2} - (sum-1) \\ 2f_{sum-1} - f_{sum-2} - (sum-1) & = 0 \\ \end{aligned} \]

构造函数 \(h_x = (sum-x+1)f_{x} - (sum-x)f_{x-1} - (sum-x)(sum-1)\),其中已知 \(h_{sum-1}=0\)

假设有 \(h_x = c\),则将 \(f_{x} = 2f_{x-1} - f_{x-2} - \frac{sum-1}{sum-i+1}\) 代入,得到:

\[\begin{aligned} h_x & = c \\ (sum-x+1)(2f_{x-1} - f_{x-2} - \frac{sum-1}{sum-x+1}) - (sum-x)f_{x-1} - (sum-x)(sum-1) & = c \\ (sum-x+1)(2f_{x-1} - f_{x-2}) - (sum-1) - (sum-x)f_{x-1} - (sum-x)(sum-1) & = c \\ (sum-x+2)f_{x-1} - (sum-x+1)f_{x-2} - (sum-x+1)(sum-1) & = c \\ h_{x-1} & = c \\ \end{aligned} \]

故,\(h_i = 0,\forall i \in [1,sum-1]\),其中,通过 \(h_1 = 0\) 我们可以得到:

\[\begin{aligned} h_1 &= sumf_{1} - (sum-1)f_{0} - (sum-1)^2 \\ sumf_{1} - (sum-1)f_{0} - (sum-1)^2 &= 0 \\ f_1 &=\frac{(sum-1)^2}{sum} \\ \end{aligned} \]

至此,得到 \(f_1\),则 \(\{ f_i \}\) 可以通过递推得到。

答案统计

设总期望为 \(E\),则 \(E = \sum_{i=1}^n f_{a_i}\)


代码实现

#include<bits/stdc++.h>
#define ll long long
#define MOD 1000000007
#define max(a,b) ((a)<(b)?(b):(a))
#define add(a,b) ((a)+(b)>=(MOD)?((a)+(b)-(MOD)):((a)+(b)<0?((a)+(b)+(MOD)):((a)+(b))))
#define mul(a,b) (1ll*(a)*(b)%(MOD))
#define tomax(a,b) ((a)=max((a),(b)))
#define toadd(a,b) ((a)=add((a),(b)))
#define tomul(a,b) ((a)=mul((a),(b)))
#define FOR(i,a,b) for(register int i=(a);i<=(b);++i)
#define main Main();signed main(){ios::sync_with_stdio(0);cin.tie(0);return Main();}signed Main
using namespace std;
const int N=25e2+10,M=1e5+10;
int n,mx,sum,ans;
int a[N],f[M];
inline int fpow(int a,int b) {
	int res=1;
	for(a%=MOD; b; b>>=1,tomul(a,a))if(b&1)tomul(res,a);
	return res;
}
inline int Inv(int x) {
	return fpow(x,MOD-2);
}
signed main() {
	cin>>n;
	FOR(i,1,n)cin>>a[i],sum+=a[i],tomax(mx,a[i]);
	f[1]=mul(mul(sum-1,sum-1),Inv(sum));
	FOR(i,2,mx)f[i]=add(add((ll)f[i-1]<<1,-f[i-2]),mul(1-sum,Inv(sum-i+1)));
	FOR(i,1,n)toadd(ans,f[a[i]]);
	cout<<ans<<endl;
	return 0;
}

提示:注意取模与逆元相关细节。


题外话

这题还有一个弱化版:Color - BZOJ 2554 - Virtual Judge (vjudge.net),可以拿来试试手。

如果你想要一个美丽的题面,可以看:Rainbow Balls - CodeForces 850F - Virtual Judge (vjudge.net)


posted @ 2024-05-02 20:49  Add_Catalyst  阅读(23)  评论(0)    收藏  举报