题目链接
题目大意
有n元钱,要赚到m元。规则是第一局压1元,输了压之前压的2倍,否则继续压1元,输赢的概率都是0.5,问赢到m元的概率是多少
题解
以“输输输……输赢”为一个周期,可以赢到一块钱。因而需要经过 m 个这样的周期,有x元可以输,赚1块的次数是2^n - 1 <= x,n就是次数。然后我们一共有[n, n + m - 1]可以输,那么输x元赚1元的概率就是1-2^n,由于m很大,有一段区间内的概率是相等的,[2^n - 1, 2^(n + 1) - 2]是相等的,所以我们就可以一次算多个区间的概率
代码
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#define x first
#define y second
#define endl '\n'
#define IOS \
ios_base::sync_with_stdio(0); \
cin.tie(0); \
cout.tie(0);
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f, mod = 998244353;
const int N = 2e5 + 10;
ll qmi(ll n, ll k, ll p = mod)
{
ll res = 1 % p;
while (k) {
if (k & 1)
res = res * n % p;
n = n * n % p;
k >>= 1;
}
return res;
}
void solve()
{
ll n, m;
cin >> n >> m;
ll ans = 1;
for (ll i = 1; (1ll << i) <= n + m; i++) {
ll l = max((1ll << i) - 1ll, n), r = min((1ll << (i + 1)) - 2ll, n + m - 1);
//从n开始花
if (l > r)
continue;
ll p = (mod + 1 - qmi((1ll << i), mod - 2)) % mod;
ans = ans * qmi(p, r - l + 1) % mod;//r-l+1代表有这么多个概率相同,所以用快速幂相乘
}
cout << ans << endl;
}
int main()
{
// IOS;
int _ = 1;
// cin >> _;
while (_--) {
solve();
}
return 0;
}