[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\) 个的概率相同,故得到式子:
因此 \(\{ 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)}\)(概率学知识,我不太懂)。
那么得到式子:
状态化简
我们求出 \(\{ 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\))。
我们继续推导:
这很明显可以用数学归纳法求解。
归纳法求解
在此我们直接求出 \(f_1\) 的值,然后就可以递推求解。
将 \(x=sum-1\) 代入式子中可得:
构造函数 \(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}\) 代入,得到:
故,\(h_i = 0,\forall i \in [1,sum-1]\),其中,通过 \(h_1 = 0\) 我们可以得到:
至此,得到 \(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)。

浙公网安备 33010602011771号