Expectation (Easy Version) 2023“钉耙编程”中国大学生算法设计超级联赛(5)hdu7330

Problem - 7330

题目大意:有n次游戏,每次游戏有a/b的概率获胜,且相互独立,如果当前赢了cnt次游戏,那么这次游戏会赢得1^{m}+2^{m}+...+cnt^{m}的分数,问最后得分的期望

1<=n<=1e6;1<=m,a<=b<998244353

思路:因为每次事件相互独立,且只有输和赢两种结果,所以是一个二项分布,但每次事件的得分不同,所以要对赢几次分别求概率和得分相乘,最后再加起来就是总的期望,得分因为是递增的,所以用一个前缀和维护,每多赢一次,sum就加上赢得次数i的m次方。

概率就是二项分布的概率,C(i,n) *(\frac{a}{b})^{i}*(\frac{b-a}{b})^{n-i},分母固定为b^{n},我们只需要维护两个分子,分子1初始化为a,分子而初始化为(b-a)^{n-1},每次求完一次,分子1*a,分子2除以b-a。

然后注意到本题数据范围是1e6,且可能有10组1e6,如果O(nlogn)的话,超过1e8级别,比较极限,所以对于组合数也要预处理,即先预处理好1~1e6的阶乘数组和阶乘逆元数组,之后C(a,b)即b!/(a!(b-a)!)就可以O(1)求出

//#include<__msvc_all_public_headers.hpp>
#include
using namespace std;
typedef long long ll;
const ll MOD = 998244353;
const int N = 1e6 + 5;
ll inv[N], fac[N];
ll C(ll x, ll y)
{//C(x,y)=y!/((y-x)!x!)
    return fac[y] * inv[x] % MOD * inv[y - x] % MOD;
}
ll qpow(ll a, ll b)
{//快速幂
    ll ret = 1;
    while (b)
    {
        if (b & 1)
        {
            ret = ret * a % MOD;
        }
        a = a * a % MOD;
        b >>= 1;
    }
    return ret;
}
int main()
{
    int t;
    cin >> t;
    fac[0] = 1;
    inv[0] = 1;
    for (ll i = 1; i <= 1000000; i++)
    {//预处理阶乘和阶乘逆元
        fac[i] = (fac[i - 1] * i) % MOD;
        inv[i] = qpow(fac[i], MOD - 2);
    }
    while (t--)
    {
        int n, m;
        ll a, b;
        cin >> n >> m >> a >> b;
        ll sum = 0;
        ll ans = 0;
        ll temp1 = a;//分子1
        ll temp2 = qpow(b-a, n - 1);//分子2
        ll temp3 = qpow(qpow(b, n), MOD - 2);//分母
        ll temp4 = qpow(b - a, MOD - 2);//分子2每次*的逆元
        for (ll i = 1; i <= n; i++)
        {//枚举n次里面赢几次的期望
            sum = (sum + qpow(i, m)) % MOD;//得分
            ll p = temp1 * temp2 % MOD * temp3 % MOD * C(i, n) % MOD;//概率
            ans = (ans + p * sum % MOD) % MOD;//期望和
            temp2 = temp2 * temp4 % MOD;
            temp1 = temp1 * a % MOD;
        }
        cout << ans << endl;
    }
    return 0;
}

你可能感兴趣的:(数论,算法,概率论,c++)