题意
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;
}