解析
二倍相邻项,就要想裂项
纯数学题
一道黑色的小凯的疑惑
设总球数为 sss
我们先钦定一种颜色留到最后,那么其他颜色可以等价考虑
设 fif_{i}fi 为钦定的颜色的球有 iii 个,涂完需要的期望次数
则有:
fi=(fi−1+fi+1)×p+fi×(1−2p)+wif_i=(f_{i-1}+f_{i+1})\times p+f_i\times (1-2p)+w_ifi=(fi−1+fi+1)×p+fi×(1−2p)+wi
其中 ppp 表示有序取出两个不同色球的概率,wiw_iwi 表示有 iii 个球的颜色留到最后的概率。
不难发现 p=i(s−i)s(s−1)p=\dfrac{i(s-i)}{s(s-1)}p=s(s−1)i(s−i),考虑如何求 wiw_iwi。
首先有: w0=0,ws=1w_0=0,w_s=1w0=0,ws=1。
和 fff 的转移类似的,有:wi=(wi−1+wi+1)×p+wi×(1−2p)w_i=(w_{i-1}+w_{i+1})\times p+w_i\times (1-2p)wi=(wi−1+wi+1)×p+wi×(1−2p)
化简移项,得:
wi+1−wi=wi−wi−1w_{i+1}-w_i=w_i-w_{i-1}wi+1−wi=wi−wi−1
也就是说 www 是一个等差数列,那么显然就有:
wi=isw_i=\frac{i}{s}wi=si
把 p,wp,wp,w 带回原来的转移式:
fi=(fi−1+fi+1)×i(s−i)s(s−1)+fi×(1−2i(s−i)s(s−1))+isf_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
化简,得:
2fi=fi+1+fi−1+s−1s−i2f_i=f_{i+1}+f_{i-1}+\frac{s-1}{s-i}2fi=fi+1+fi−1+s−is−1
也就是:
fi−fi+1=fi−1+fi+s−1s−if_i-f_{i+1}=f_{i-1}+f_{i}+\frac{s-1}{s-i}fi−fi+1=fi−1+fi+s−is−1
把 i=1i=1i=1 带入,有:
f2=2f1+1f_2=2f_1+1f2=2f1+1
又有:
f1=f1−fs=∑i=2s(fi−1−fi)=(s−1)(f1−f2)+∑i=2s−1s−1s−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−1s−i\dfrac{s-1}{s-i}s−is−1,它会产生 s−is-is−i 次贡献。
把 f2=2f1+1f_2=2f_1+1f2=2f1+1 带入,得到:
f1=(s−1)2sf_1=\frac{(s-1)^2}{s}f1=s(s−1)2
得到 f1f_1f1 之后,后面顺推即可。
过程中快速幂求逆元,时间复杂度 O(nlogmod)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);
#endifn=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;
}
/*
*/