[CF850F]Rainbow Balls

\(\text{Tip}\):感谢此篇题解对我的巨大帮助,故记录一下式子的推导过程。

\(\text{Problem}\)题目链接

\(\text{Solution}\)

有多种颜色的球,且要求最后剩下的球颜色相同。故考虑枚举最后留下的球的颜色 \(x\)

\(F_{i}\) 表示当前有 \(i\) 个颜色为 \(x\) 的球,把所有球都变成颜色为 \(x\) 的期望时间,再记 \(S\) 表示球的总和,即 \(S=\sum\limits_{i=1}^{n}a_{i}\)。显然 \(F_{0}\) 这个状态不存在,且 \(F_{S}=0\)。记 \(P_{i}\) 表示当前有 \(i\) 个颜色为 \(x\) 的球时,选出两个球颜色不同且其中至少有一个球颜色为 \(x\) 的概率,则 \(P_{i}=\cfrac{i(s-i)}{s(s-1)}\)。记 \(v_{i}\) 表示每次转移时贡献的期望时间,则对于 \(\forall i\in[1,S-1]\)易得:

\[\qquad F_{i}=P_{i}(F_{i-1}+F_{i+1})+(1-2P_{i})F_{i}+v_{i} \qquad \]

此处有个很关键的地方,就是 \(v_{i}\not=1\)。考虑其原因,发现当 \(i\leq0\) 时答案不存在,所以需要考虑能从 \(i\) 到达 \(S\) 的贡献,而走一步的期望就相当于 \(i\) 能走到 \(S\) 的概率。而这是个经典问题,简述为:数轴上有一个点 \(p\) 每次等概率向左或向右走,也可以不走,问能走到 \(S\) 的概率。该问题解法如下:

\(G_{i}\) 表示从 \(i\) 能走到 \(S\) 的概率,那么有:

\[\qquad G_{i}=P_{i}(G_{i-1}+G_{i+1})+(1-2P_{i})G_{i} \qquad \]

其中边界条件显然为 \(G_{0}=0,G_{S}=1\)。上式可解得 \(2G_{i}=G_{i-1}+G_{i+1}\)。发现 \(G_{i+1}-G_{i}=G_{i}-G_{i-1}\),则对于数列 \(\{G_{i}-G_{i-1}\}(1\leq i\leq S)\),构成一个等差数列 。

故得到 \(G_{i}=\cfrac{i}{S}\)

于是 \(v_{i}=G_{i}=\cfrac{i}{S}\),则转移方程为:

\[\qquad F_{i}=P_{i}(F_{i-1}+F_{i+1})+(1-2P_{i})F_{i}+\cfrac{i}{S} \qquad \]

着手拆开这个式子,得到:

\[\qquad 2P_{i}F_{i}=P_{i}(F_{i-1}+F_{i+1})+\cfrac{i}{S} \qquad \]

\(P_{i}=\frac{i(S-i)}{S(S-1)}\) 代入,得到:

\[\qquad 2F_{i}=F_{i-1}+F_{i+1}+\cfrac{S-1}{S-i} \qquad \]

\[\qquad F_{i}-F_{i+1}=F_{i-1}-F_{i}+\cfrac{S-1}{S-i} \qquad \]

发现通过这个式子,可以对于所有的 \(i\in[2,S]\),把 \(F_{i-1}-F_{i}\) 转换为 \(F_{1}-F_{2}\),考虑求出它。

发现 \(F_{0}\) 不存在。于是对于 \(i=1\),可以算出:

\[\qquad F_{1}=F_{2}P_{1}+(1-2P_{1})F_{1}+\cfrac{1}{S} \qquad \]

\[\qquad 2P1F_{1}=P_{1}F_{2}+\cfrac{1}{S} \qquad \]

发现 \(P_{1}=\frac{1}{S}\),则得到:\(F_{2}=2F_{1}-1\)

故考虑如何使用上面的关键性质。发现 \(F_{S}=0\),则 \(F_{1}=F_{1}-F_{S}\),故有:

\[\qquad F_{1}-F_{S}=\sum\limits_{i=2}^{S}F_{i-1}-F_{i} \qquad \]

考虑如何快速的把 \(F_{i-1}-F_{i}\) 快速转化为与 \(F_{1}-F_{2}\) 有关的式子:

\[\qquad F_{i-1}-F_{i}=F_{1}-F_{2}+\sum\limits_{j=2}^{i-1}\cfrac{S-1}{S-j} \qquad \]

发现对于 \(\sum\limits_{i=2}^{S}F_{i-1}-F_{i}\) 来说,不必 \(O(S^2)\) 爆求式子的原因是后面枚举贡献的式子重复。发现对于 \(j\) 来说,计算 \(\cfrac{S-1}{S-j}\) 的次数为 \((S-j)\) 次。则得到:

\[\qquad \sum\limits_{i=2}^{S}F_{i-1}-F_{i}=(S-1)(F_{1}-F_{2})+\sum\limits_{j=2}^{S-1}(S-1) \qquad \]

于是把 \(F_{2}=2F_{1}-1\) 代入上式,即可用 \(S\) 表达出 \(F_{1}\)

\[\qquad F_{1}=\cfrac{(S-1)^2}{S} \qquad \]

然后我们可以通过 \(F_{1}\) 求出 \(F_{2}\),那么可以直接通过 \(O(S\log P)\) 的时间复杂度求出 \(F\) 的每一项(\(P\) 为本题中的模数)。

发现 \(S=\sum\limits_{i=1}^{n}a_{i}\approx 2.5\times 10^{8}\),数组开不下。考虑最终答案是 \(\sum\limits_{i=1}^{n}F_{a_{i}}\),故记 \(W=max\{a_{i}\}\),我们只需要求到 \(F_{W}\) 即可,时间复杂度为 \(O(W\log P)\),空间复杂度为 \(O(W)\),发现 \(W\leq10^{5}\),可以通过本题。

\(\text{Code}\)

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
#include <stack>
#include <map>
#include <bitset>
#define ri register
#define inf 0x7fffffff
#define E (1)
#define mk make_pair
#define int long long
//#define double long double
using namespace std; const int N=200010, Mod=1e9+7;
inline int read()
{
    int s=0, w=1; ri char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch-'0'), ch=getchar();
    return s*w;
}
void print(int x) { if(x<0) x=-x, putchar('-'); if(x>9) print(x/10); putchar(x%10+'0'); }
int n,a[N],dp[N],S;
inline int ksc(int x,int p) { int res=1; for(;p;p>>=1, x=x*x%Mod) if(p&1ll) res=res*x%Mod; return res; }
signed main()
{
    n=read();
    for(ri int i=1;i<=n;i++) a[i]=read(), S+=a[i];
    dp[1]=ksc(S,Mod-2)%Mod*(S-1)%Mod*(S-1)%Mod;
    dp[2]=dp[1]*2-1, dp[2]%=Mod;
    for(ri int i=3;i<=min((int)1e5,S-1);i++) dp[i]=(dp[i-1]*2-dp[i-2]-(S-1)%Mod*ksc(S-i+1,Mod-2)%Mod)%Mod, dp[i]=(dp[i]+Mod)%Mod;
    int res=0;
    for(ri int i=1;i<=n;i++) res=(res+dp[a[i]])%Mod;
    printf("%lld\n",res);
    return 0;
}
posted @ 2020-08-09 15:58  zkdxl  阅读(112)  评论(9编辑  收藏  举报