题目描述
给定 n n n 种颜色的球,每种球有 a i a_i ai 个,对这些球执行以下操作:
- 有顺序地任意取两个球,将第二个球涂上第一个球的颜色,重复该操作至所有球颜色相同。
求期望操作次数,对
1
0
9
+
7
10^9+7
109+7 取模。
数据范围:
n
≤
2500
n\le 2500
n≤2500,
1
≤
a
i
≤
1
0
5
1\le a_i\le 10^5
1≤ai≤105。
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×(s−1)i×(s−i) 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×fi−1+p×fi+1+(1−2p)×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×gi−1+p×gi+1+(1−2p)×gi。
转化可得 g i − g i − 1 = g i + 1 − g i g_i-g_{i-1}=g_{i+1}-g_{i} gi−gi−1=gi+1−gi,等差数列求和可得 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×fi−1+p×fi+1+(1−2p)×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} fi−fi+1=fi−1−fi+s−is−1
- 考虑求
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=2f1−1。
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=f1−fs=i=2∑sfi−1−fi=(s−1)×(f1−f2)+i=2∑s−1s−is−1×(s−i)=(s−1)×(1−f1)+(s−1)×(s−2) - 所以 f 1 = ( s − 1 ) 2 s f_1=\frac{(s-1)^2}{s} f1=s(s−1)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;
}