[CF850F] Rainbow Balls

题目链接

题目描述

给定 n n n 种颜色的球,每种球有 a i a_i ai 个,对这些球执行以下操作:

  • 有顺序地任意取两个球,将第二个球涂上第一个球的颜色,重复该操作至所有球颜色相同。

求期望操作次数,对 1 0 9 + 7 10^9+7 109+7 取模。
数据范围: n ≤ 2500 n\le 2500 n2500 1 ≤ a i ≤ 1 0 5 1\le a_i\le 10^5 1ai105

Solution

  • f i f_i fi 表示当前有 i i i 个球,将所有球变为该颜色的期望次数, s s s 表示球的总数, p p p 表示当前取出的两个球第一个与最终颜色相同,第二个与最终颜色不同的概率。
    根据题意,有 p = i × ( s − i ) s × ( s − 1 ) p=\frac{i\times(s-i)}{s\times(s-1)} p=s×(s1)i×(si) f i = p × f i − 1 + p × f i + 1 + ( 1 − 2 p ) × f i + v f_i=p\times f_{i-1}+p\times f_{i+1}+(1-2p)\times f_i+v fi=p×fi1+p×fi+1+(12p)×fi+v其中 v v v 为这一步操作对最终答案的贡献,也就是该颜色成为最终颜色的概率。
  • g i g_i gi 表示当前颜色成为最终颜色的概率,有 g 0 = 0 g_0=0 g0=0 g 1 = 1 g_1=1 g1=1,且 g i = p × g i − 1 + p × g i + 1 + ( 1 − 2 p ) × g i g_{i}=p\times g_{i-1}+p\times g_{i+1}+(1-2p)\times g_i gi=p×gi1+p×gi+1+(12p)×gi
    转化可得 g i − g i − 1 = g i + 1 − g i g_i-g_{i-1}=g_{i+1}-g_{i} gigi1=gi+1gi,等差数列求和可得 g i = i s g_i=\frac{i}{s} gi=si,即 v = i s v=\frac{i}{s} v=si
  • 那么现在有 f i = p × f i − 1 + p × f i + 1 + ( 1 − 2 p ) × f i + i s f_i=p\times f_{i-1}+p\times f_{i+1}+(1-2p)\times f_i+\frac{i}{s} fi=p×fi1+p×fi+1+(12p)×fi+si转化后有 f i − f i + 1 = f i − 1 − f i + s − 1 s − i f_{i}-f_{i+1}=f_{i-1}-f_{i}+\frac{s-1}{s-i} fifi+1=fi1fi+sis1
  • 考虑求 f 1 f_1 f1 f 2 f_2 f2 后线性递推,由于 f 0 f_0 f0 不存在,代入后有 f 2 = 2 f 1 − 1 f_2=2f_1-1 f2=2f11
    f 1 = f 1 − f s = ∑ i = 2 s f i − 1 − f i = ( s − 1 ) × ( f 1 − f 2 ) + ∑ i = 2 s − 1 s − 1 s − i × ( s − i ) = ( s − 1 ) × ( 1 − f 1 ) + ( s − 1 ) × ( s − 2 ) \begin{aligned}f_1&=f_1-f_s\\ &=\sum_{i=2}^{s}{f_{i-1}-f_{i}}\\ &=(s-1)\times(f_1-f_2)+\sum_{i=2}^{s-1}{\frac{s-1}{s-i}\times(s-i)}\\&=(s-1)\times(1-f_1)+(s-1)\times(s-2)\end{aligned} f1=f1fs=i=2sfi1fi=(s1)×(f1f2)+i=2s1sis1×(si)=(s1)×(1f1)+(s1)×(s2)
  • 所以 f 1 = ( s − 1 ) 2 s f_1=\frac{(s-1)^2}{s} f1=s(s1)2线性递推即可求解,答案为 ∑ i = 1 n f a i \sum_{i=1}^{n}{f_{a_{i}}} i=1nfai

Code

#include<cstdio>
using namespace std;
const int maxn=100010,MLY=1000000007;
int f[maxn],n,a[maxn],s,ans;
inline int power(int a,int b){
	int ans=1;
	while(b){
		if(b&1)ans=1ll*ans*a%MLY;
		a=1ll*a*a%MLY;
		b>>=1;
	}
	return ans;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i)scanf("%d",&a[i]),s+=a[i];
	f[1]=(s-1ll)*(s-1)%MLY*power(s,MLY-2)%MLY;
	f[2]=(2ll*f[1]-1+MLY)%MLY;
	for(int i=2;i<100000;++i)
		f[i+1]=((2ll*f[i]-f[i-1]-(s-1ll)*power(s-i,MLY-2))%MLY+MLY)%MLY;
	for(int i=1;i<=n;++i)ans=(ans+f[a[i]])%MLY;
	printf("%d",ans);
	return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

x7103

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值