j题的题解思路

首先要知道逆元,快速幂,费马小定理。链接都在下文中;

首先是要求得概率,输赢之后加一元,输输赢也是加一元,以此类推有非常多种组合,故我们只需要计算连输之后破产的概率,用一减去就是赢到m+n元的概率。

所以我们要计算最大连输的次数设为R,当n=1,m=1时R=0,当n=2,m=1时,R=1,当n=3,m=1时,R=2……n=x,m=y时,R=log2(x+1);

赢的概率就是1-½^R

计算得到的概率是个除法,但是答案要求对其取模,而在模运算中不能有除法,所以我们要将其转化为乘法。

转化要用到的知识是逆元。:https://zhuanlan.zhihu.com/p/378728642 看这个就行。

之后就可以把1-½^R-->1-2^R的逆元,两个是一样的。

之后在计算中要用快速幂计算2^R,再用费马小定理得到这个的逆元。

注意每一步计算出的概率都要取模,原因是取模运算会减小值,防止数据过大溢出,并且根据同余理论,ab%m==(a%m)(b%m)%m,这样步步取模不会影响结果。

PS:(要用到快速幂取:以下是快速幂取模算法的推导文章

https://blog.csdn.net/chen_zan_yu_/article/details/90522763

x & 1的意思是判断奇偶性//a=(a*a)%c就是公式中的a^2,b=b/2同理,b>>=1就等于b/=2;b<<n左移一位都相当于乘以2的1次方,左移n位就相当于乘以2的n次方。 P-2是费马小定理中求逆元的方法)

#include<bits/stdc++.h>
using namespace std;
#define MOD 998244353
typedef long long ll;
ll ksm(ll a, ll b)
{
    ll ret = 1;
    a = a % MOD;
    while(b>0) {
        if(b % 2 == 1)
        ret = (ret * a) % MOD;
        b = b/2;
        a = (a * a) % MOD;
    }
    return ret;
}
ll niyuan(ll a){
   return ksm(a, MOD-2);
}//求解逆元
int main(){
    ll n,m,k,ans;
    cin>>n>>m;
    m+=n;
    ans=1;
    //cout<<(3*niyuan(8))%MOD;样例一的8的逆元是niyuan(8)根据公式a*bmod(m)=a*a^m-2(费马小定理)
    while(n<m){
        ll zuixiao=log2(n+1);//最小的可连输的数量
        ll next=min(m,(ll)pow(2,zuixiao+1)-1);//更新n的值
        ll p=(1-niyuan(ksm(2,zuixiao))+MOD)%MOD;//赢的概率,+MOD是防止负数
        ans=ans*ksm(p,next-n)%MOD;//相同概率的个数
        n=next;
    }
    cout<<ans<<"\n";
    return 0;
}