J Roulette(“范式杯”2023牛客暑期多校训练营1)

 

题意

Walk Alone 初始有 n 块钱,如果每次投 x 元,有一半的概率输掉这 x 元,另
一半概率赢得 2 x 元。现在 Walk Alone 采取下述策略投注:
如果上一把赢了,这一把投 x i = 1
如果上一把输了,这一把投 x i = 2 x i 1 元。
Walk Alone 有多大概率拿到 n + m 元离开。
1 n , m 10 9

题解:

思路在代码注释上

#include <bits/stdc++.h>
using namespace std;
const int MOD = 998244353;
typedef long long ll;
ll n, m;
ll qpow(ll a, ll b)//快速幂
{
    a %= MOD;
    ll ans = 1;
    while (b > 0)
    {
        if (b & 1)
        {
            ans = ans * a % MOD;
        }
        a = a * a % MOD;
        b >>= 1;
    }
    return ans % MOD;
}
ll inv(ll x)
{ // 逆元
    return qpow(x, MOD - 2);
}
int main()
{
    cin >> n >> m;
    ll res = 1;
    for (ll i = n; i < n + m;) // i表示当前的钱,超过n+m结束
    {
        ll rc = (ll)log2(i + 1); // 当有i块钱时至多能连输r把,即至少能打r把
        /*
        输1  2  3  4  5 …… i把
      赌注1  2  4  8  16   2^(i-1)
      所以连输i把总计输掉1+4+8+16+……+2^(i-1) = 2^i-1块
      若当前有x块,则其至多能打i把,满足2^i-1<=x---->i<=log2(x+1)
      若可继续,当进行下一次赌注时,赌注为2^i,若这一把赢了就会赢回本金且赚一块,形式为(输输)……赢
        */
        ll p = (1 - inv(qpow(2, rc)) + MOD) % MOD; // 用至少能打rc场比赛的钱挣1块钱的概率,这里概率用逆元表示
        /*
        假设你现在能打i把,其中你每赢一把,下一次赌注为1,示为另一轮开始。
        当你利用能打i把比赛的本金赢一块的情况有:赢/输赢/输输赢……,概率分别为0.5、0.5^2、0.5^3……
        等比数列求和为1-0.5^i
        */
        ll r = min(n + m - 1, (1ll << (rc + 1)) - 2); // 这是本金的右区间,因为大于n+m就会退出,不要多算了
        /*
        直接用本金区间计算而不是用单个本金值进行计算,这里就对应后面本金的跳转为r+1
        因为本金在区间2^i-1 ~ 2^(i+1)-2都是至多输i场比赛
        */
        res = res * qpow(p, r - i + 1) % MOD; // 表示每次以这个场次赢一块,直至这个区间结束的总的概率,区间的长度就是你赢了多少块,进行了多少次rc
        i = r + 1;                            // 下一区间开始
    }
    cout << res << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值