CF850F Rainbow Balls

本文介绍了一种使用动态规划(DP)解决染色球问题的方法,通过推导DP方程,求解将一组球统一成单一颜色所需的期望时间。文章详细解释了状态转移方程的推导过程,并给出了解决方案的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先可以枚举最后的球都是什么颜色

\(f_i\) 表示当前有 \(i\) 个钦定的颜色的球,把所有球都变成这种颜色的期望时间

显然 \(f_0\) 不存在

\(s=\sum_{i=1}^{n}a_i\) 那么 \(f_s=0\)

对于 \(0<i<s\) 可以得到一个 \(DP\) 方程

\[f_i=(f_{i-1}+f_{i+1})p+(1-2p)f_i+v\]

其中 \(p\) 表示选出两个球不同色的概率 \(\frac{i(s-i)}{s(s-1)}\)\(v\) 表示贡献的期望时间

注意不是 \(1\)!!!

结论就是 \(v=\frac{i}{s}\)

考虑 \(v\) 是个什么东西下面纯属瞎bb

由于不能到 \(0\) 这个状态,所以 \(i\) 只能算到达那些走到 \(s\) 的贡献

那么 \(v\) 相当于走到 \(s\) 的概率,也就是走一步的期望

也就是数轴上一个点 \(x\) 每次等概率向左或者向右走,求走到 \(0\) 之前到达 \(s\) 的概率

这个是个经典问题

\(g_i\) 表示 \(i\)\(s\) 的概率,那么 \(g_0=0,g_s=1\)

\(g_i=pg_{i-1}+pg_{i+1}+(1-2p)g_i\)

那么 \(g_i-g_{i-1}=g_{i+1}-g_i\)

可以得到概率为 \(\frac{i}{s}\)

瞎bb完了

那么现在有一个方程

\[f_i=(f_{i-1}+f_{i+1})p+(1-2p)f_i+\frac{i}{s} \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (1)\]

由于 \(f_0\) 不存在那么

\[f_1=f_2p+(1-2p)f_1+\frac{1}{s}\]

\(f_2=2f_1-1\)

\((1)\) 可以得到

\[f_i-f_{i+1}=f_{i-1}-f_i+\frac{s-1}{s-i} \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (2)\]

所以

\[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}(s-i)\]

代入 \(f_2=2f_1-1\) 得到

\[f_1=\frac{(s-1)^2}{s}\]

那么求出 \(f_2\) 之后,根据 \((2)\) 就可以推出所有的 \(f\)

最后答案就是 \(\sum_{i=1}^{n}f_{a_i}\)

# include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int mod(1e9 + 7);
const int maxn(1e5 + 5);

int mx = 1e5, n, cnt[maxn], sum, f[maxn], ans;

inline void Inc(int &x, int y) {
    if ((x += y) >= mod) x -= mod;
}

inline int Pow(ll x, int y) {
    register ll ret = 1;
    for (; y; y >>= 1, x = x * x % mod)
        if (y & 1) ret = ret * x % mod;
    return ret;
}

int main() {
    scanf("%d", &n);
    register int i;
    for (i = 1; i <= n; ++i) scanf("%d", &cnt[i]), sum += cnt[i];
    f[1] = 1LL * (sum - 1) * (sum - 1) % mod * Pow(sum, mod - 2) % mod;
    f[2] = (2 * f[1] % mod + mod - 1) % mod;
    for (i = 2; i < mx; ++i)
        f[i + 1] = ((2 * f[i] % mod - f[i - 1] + mod) % mod - 1LL * (sum - 1) * Pow(sum - i, mod - 2) % mod + mod) % mod;
    for (i = 1; i <= n; ++i) Inc(ans, f[cnt[i]]);
    printf("%d\n", ans);
    return 0;
}

转载于:https://www.cnblogs.com/cjoieryl/p/9896023.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值