【题目】
CF
袋子里有
n
n
n种颜色的球,第
i
i
i个颜色有
a
i
a_i
ai个,当袋子里有两种或以上颜色球时,连续取出两个球,并将第二个球涂成第一个球的颜色,再将两个球放回去。求期望时间对
1
e
9
+
7
1e9+7
1e9+7取模。
n
≤
2500
,
a
i
≤
1
0
5
n\leq 2500,a_i\leq 10^5
n≤2500,ai≤105
【解题思路】
设
s
=
∑
a
i
s=\sum a_i
s=∑ai
首先我们可以枚举最后剩下的颜色,设
f
i
f_i
fi表示当前有
i
i
i个这种颜色球时,所有球都变成这个颜色的期望,那么
f
0
f_0
f0不存在,
f
s
=
0
f_s=0
fs=0。
这个问题实际上可以转化为一个序列上的随机游走问题:一个长度为
s
+
1
s+1
s+1的序列,位置编号
0
∼
s
0\sim s
0∼s,在
0
<
i
<
s
0<i<s
0<i<s的地方向前后的概率是相等的,在序列的两头会停下来。
这个是一个经典的赌徒破产问题,设状态为当前在某个点到达端点的概率,我们可以将方程表示成常系数线性递推的关系,解特征根方程来做。巧合的是这个问题在考前数学组的同学来问过我然后我随便搞了一下就搞出来了。
由于概率相等比较特殊,我们不妨设从 i i i走到 s s s的概率为 p i p_i pi,那么我们有 p 0 = 0 , p s = 1 , p i = p i − 1 + p i + 1 2 ( 0 < i < s ) p_0=0,p_s=1,p_i=\frac{p_{i-1}+p_{i+1}} 2(0<i<s) p0=0,ps=1,pi=2pi−1+pi+1(0<i<s),然后 p i + 1 − p i = p i − p i − 1 p_{i+1}-p_i=p_i-p_{i-1} pi+1−pi=pi−pi−1,就是一个等差数列的形式了。
于是不难得到在 i i i点走到 s s s的概率为 i s \frac i s si,那么走到 0 0 0就是 s − i s \frac {s-i} s ss−i
这样依赖我们就可以列出
f
f
f的方程,设
p
p
p表示选出两个不同色球的概率,那么这里
p
=
i
(
s
−
i
)
s
(
s
−
1
)
p=\frac {i(s-i)} {s(s-1)}
p=s(s−1)i(s−i):
f
i
=
p
(
f
i
−
1
+
f
i
+
1
)
+
(
1
−
2
p
)
f
i
+
i
s
(
0
<
i
<
s
)
f_i=p(f_{i-1}+f_{i+1})+(1-2p)f_i+\frac i s(0<i<s)
fi=p(fi−1+fi+1)+(1−2p)fi+si(0<i<s)
这里显然可以高斯消元做到 O ( ( ∑ a i ) 3 ) O((\sum a_i)^3) O((∑ai)3)
考虑化简这个方程,由于没有
f
0
f_0
f0,我们可以得到:
f
1
=
p
f
2
+
(
1
−
2
p
)
f
1
+
1
s
f_1=pf_2+(1-2p)f_1+\frac 1 s
f1=pf2+(1−2p)f1+s1
即
f
2
=
2
f
1
−
1
f_2=2f_1-1
f2=2f1−1
又因为(我们将原式移项):
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
−
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
)
f_1=f_1-f_s=\sum_{i=2}^sf_{i-1}-f_i=(s-1)(f_1-f_2)+\sum_{i=2}^{s-1}\frac {s-1}{s-i}(s-i)
f1=f1−fs=i=2∑sfi−1−fi=(s−1)(f1−f2)+i=2∑s−1s−is−1(s−i)
回代得:
f
1
=
(
s
−
1
)
2
s
f_1=\frac {(s-1)^2} s
f1=s(s−1)2
于是我们可以求出
f
2
f_2
f2,然后就可以递推出所有的
f
f
f了。
最后答案就是
∑
i
=
1
n
f
a
i
\sum_{i=1}^n f_{a_i}
∑i=1nfai
复杂度
O
(
n
+
max
{
a
i
}
)
O(n+\max \{a_i\})
O(n+max{ai})
【参考代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10,mod=1e9+7;
int n,mx,sum,ans;
int a[N],f[N];
int qpow(int x,int y)
{
int res=1;
for(;y;y>>=1,x=(ll)x*x%mod)if(y&1)res=(ll)res*x%mod;
return res;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("CF850F.in","r",stdin);
freopen("CF850F.out","w",stdout);
#endif
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]),mx=max(mx,a[i]),sum+=a[i];
f[1]=(ll)(sum-1)*(sum-1)%mod*qpow(sum,mod-2)%mod;
for(int i=1;i<mx;++i)
f[i+1]=((ll)f[i]*2-f[i-1]-(ll)(sum-1)*qpow(sum-i,mod-2)%mod+mod*2)%mod;
for(int i=1;i<=n;++i) ans=(ans+f[a[i]])%mod;
printf("%d\n",ans);
return 0;
}