解析
二倍相邻项,就要想裂项
纯数学题
一道黑色的小凯的疑惑
设总球数为
s
s
s
我们先钦定一种颜色留到最后,那么其他颜色可以等价考虑
设
f
i
f_{i}
fi 为钦定的颜色的球有
i
i
i 个,涂完需要的期望次数
则有:
f
i
=
(
f
i
−
1
+
f
i
+
1
)
×
p
+
f
i
×
(
1
−
2
p
)
+
w
i
f_i=(f_{i-1}+f_{i+1})\times p+f_i\times (1-2p)+w_i
fi=(fi−1+fi+1)×p+fi×(1−2p)+wi
其中
p
p
p 表示有序取出两个不同色球的概率,
w
i
w_i
wi 表示有
i
i
i 个球的颜色留到最后的概率。
不难发现
p
=
i
(
s
−
i
)
s
(
s
−
1
)
p=\dfrac{i(s-i)}{s(s-1)}
p=s(s−1)i(s−i),考虑如何求
w
i
w_i
wi。
首先有:
w
0
=
0
,
w
s
=
1
w_0=0,w_s=1
w0=0,ws=1。
和
f
f
f 的转移类似的,有:
w
i
=
(
w
i
−
1
+
w
i
+
1
)
×
p
+
w
i
×
(
1
−
2
p
)
w_i=(w_{i-1}+w_{i+1})\times p+w_i\times (1-2p)
wi=(wi−1+wi+1)×p+wi×(1−2p)
化简移项,得:
w
i
+
1
−
w
i
=
w
i
−
w
i
−
1
w_{i+1}-w_i=w_i-w_{i-1}
wi+1−wi=wi−wi−1
也就是说
w
w
w 是一个等差数列,那么显然就有:
w
i
=
i
s
w_i=\frac{i}{s}
wi=si
把
p
,
w
p,w
p,w 带回原来的转移式:
f
i
=
(
f
i
−
1
+
f
i
+
1
)
×
i
(
s
−
i
)
s
(
s
−
1
)
+
f
i
×
(
1
−
2
i
(
s
−
i
)
s
(
s
−
1
)
)
+
i
s
f_i=(f_{i-1}+f_{i+1})\times \dfrac{i(s-i)}{s(s-1)}+f_i\times (1-\dfrac{2i(s-i)}{s(s-1)})+\frac{i}{s}
fi=(fi−1+fi+1)×s(s−1)i(s−i)+fi×(1−s(s−1)2i(s−i))+si
化简,得:
2
f
i
=
f
i
+
1
+
f
i
−
1
+
s
−
1
s
−
i
2f_i=f_{i+1}+f_{i-1}+\frac{s-1}{s-i}
2fi=fi+1+fi−1+s−is−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
把
i
=
1
i=1
i=1 带入,有:
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
)
f_1=f_1-f_s=\sum_{i=2}^s(f_{i-1}-f_i)=(s-1)(f_1-f_2)+\sum_{i=2}^{s-1}\frac{s-1}{s-i}\times(s-i)
f1=f1−fs=i=2∑s(fi−1−fi)=(s−1)(f1−f2)+i=2∑s−1s−is−1×(s−i)
后面那个和式是由于对于一个
s
−
1
s
−
i
\dfrac{s-1}{s-i}
s−is−1,它会产生
s
−
i
s-i
s−i 次贡献。
把
f
2
=
2
f
1
+
1
f_2=2f_1+1
f2=2f1+1 带入,得到:
f
1
=
(
s
−
1
)
2
s
f_1=\frac{(s-1)^2}{s}
f1=s(s−1)2
得到
f
1
f_1
f1 之后,后面顺推即可。
过程中快速幂求逆元,时间复杂度
O
(
n
log
m
o
d
)
O(n\log \bmod)
O(nlogmod)。
代码
(式子推完代码几乎没有任何难度了…)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=2e5+100;
const int mod=1e9+7;
inline ll read(){
ll x(0),f(1);char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m;
inline ll ksm(ll x,ll k){
ll res(1);
while(k){
if(k&1) res=res*x%mod;
x=x*x%mod;k>>=1;
}
return res;
}
ll a[N];
ll s,f[N],mx;
signed main() {
#ifndef ONLINE_JUDGE
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
#endif
n=read();
for(int i=1;i<=n;i++) a[i]=read(),s+=a[i],mx=max(mx,a[i]);
f[1]=(s-1)*(s-1)%mod*ksm(s,mod-2)%mod;
f[2]=(2*f[1]-1+mod)%mod;
for(int i=2;i<mx;i++) f[i+1]=(2*f[i]-f[i-1]+mod-(s-1)*ksm(s-i,mod-2)%mod+mod)%mod;
ll ans(0);
for(int i=1;i<=n;i++) (ans+=f[a[i]])%=mod;
printf("%lld\n",ans);
return 0;
}
/*
*/