记录.001

dp+数学计算

题目链接

F - Bomb Game 2

题意

已知一个整数n∈[2, 3000]

对于循环操作“将第一个人移至队伍末尾或者移出队伍(概率皆为1/2)”直到剩下最后一人

求每个位置i(1 ≤ i ≤ n)的人成为最后剩下的人的概率是多少

思考

只有一个人,第一个人留下的概率是1

两个人的时候,

始:1 2

1/2:2 或 2 1

1/4: 1 或 1 2

……

第一个人留下概率:1/21+1/23+1/25+... ≈ 0.66666

第二个人留下概率:1/22+1/24+1/26+... ≈ 0.33333

则答案为1: 2,即 1/3 和 2/3

但当人数n更大的时候就无法快速计算答案且不好代码实现,所以考虑通过dp的方式解决问题

题解

用dp方法求解,建立n^2的二维数组,其中 dp[i] [j]表示剩i个人的时候第j位置的人最后留下的概率 (j <= i)

dp[1][1] = 1
​
dp[i][1] =  1 / 2 * dp[i][i] 第一个人剩下的概率是第一个人不被移走而被移到最后一个的位置的时候 最后一个位置成功的概率
​
dp[i][j] =  1 / 2 * dp[i][j - 1] 当第j的前一个位置被移到最后一位 j就变成了j-1的位置
          + 1 / 2 * dp[i - 1][j - 1] 当j的前一个位置被移走 j变成了j-1的位置 总共剩下i-1个数字
          

则有假设剩i个人的时候 每个位置的成功概率:

设dp[i] [i] 为 x; a, b...为常数,是上一层已经求出来的答案

1         2                             3                                                 ...    i

\frac{1}{2}x      \frac{1}{2} * (\frac{1}{2}x) + \frac{1}{2}a      \frac{1}{2}*(\frac{1}{2} * (\frac{1}{2}x) + \frac{1}{2}a) + \frac{1}{2}b             x

x = \frac{1}{2^{i}}x+\frac{1}{2^{i-1}}a+\frac{1}{2^{i-2}}b+...+\frac{1}{2^{1}}k

\frac{2^{i}-1}{2^{i}}x = \frac{1}{2^{i-1}}a+\frac{1}{2^{i-2}}b+...+\frac{1}{2^{1}}k

x =\frac{\frac{1}{2^{i-1}}a+\frac{1}{2^{i-2}}b+...+\frac{1}{2^{1}}k}{\frac{2^{i}-1}{2^{i}}}

ac代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int long long
const int maxn = 1e6 + 10;
const int mod1 = 1e9 + 7;
const int mod2 = 998244353;
​
string Y = "Yes\n";
string N = "No\n";
​
int ksm(int a, int b, int mod) {
    int ans = 1;
    while (b) {
        if (b & 1) {
            ans = ans * a % mod;
        }
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}
​
int dp[3010][3010], box[3010];
​
void solve() {
    int n;
    cin >> n;
    box[0] = 1;
    for (int i = 1; i <= n; i++) {
        box[i] = box[i - 1] * 2 % mod2;
    }
    dp[1][1] = 1;
    for (int i = 2; i <= n; i++) {
        int x = 0;
        for (int j = 1; j <= i - 1; j++) {
            x = x + box[j] * dp[i - 1][j] % mod2;
            x %= mod2;
        }
        int y = (box[i] - 1 + mod2) % mod2;
        x = x * ksm(y, mod2 - 2, mod2) % mod2; // dp[i][i]
        dp[i][i] = x, dp[i][1] = x * ksm(2, mod2 - 2, mod2) % mod2;
        for (int j = 2; j <= i - 1; j++) {
            dp[i][j] = (dp[i][j - 1] + dp[i - 1][j - 1]) % mod2 * ksm(2, mod2 - 2, mod2) % mod2;
            dp[i][j] %= mod2;
        }
    }
    for (int i = 1; i <= n; i++) {
        cout << dp[n][i] << " ";
    }
}
​
signed main() {
    ios::sync_with_stdio(false);
    cin.tie();
    cout.tie();
​
    int yq = 1;
​
//    cin >> yq;
​
    while (yq--) {
        solve();
    }
    return 0;
}

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

超高校级のDreamer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值