P8774 [蓝桥杯 2022 省 A] 爬树的甲壳虫(概率DP)

发布时间 2023-03-26 20:24:03作者: 何太狼

[蓝桥杯 2022 省 A] 爬树的甲壳虫

题目描述

有一只甲壳虫想要爬上一颗高度为 \(n\) 的树,它一开始位于树根, 高度为 \(0\),当它尝试从高度 \(i-1\) 爬到高度为 \(i\) 的位置时有 \(P_{i}\) 的概率会掉回树根, 求它从树根爬到树顶时, 经过的时间的期望值是多少。

输入格式

输入第一行包含一个整数 \(n\) 表示树的高度。

接下来 \(n\) 行每行包含两个整数 \(x_{i}, y_{i}\), 用一个空格分隔,表示 \(P_{i}=\frac{x_{i}}{y_{i}}\)

输出格式

输出一行包含一个整数表示答案,答案是一个有理数,请输出答案对质数 \(998244353\) 取模的结果。其中有理数 \(\frac{a}{b}\) 对质数 \(P\) 取模的结果是整数 \(c\) 满足 \(0 \leq c<P\)\(c \cdot b \equiv a(\bmod P)\)

样例 #1

样例输入 #1

1
1 2

样例输出 #1

2

样例 #2

样例输入 #2

3
1 2
3 5
7 11

样例输出 #2

623902744

提示

对于 \(20 \%\) 的评测用例, \(n \leq 2,1 \leq x_{i}<y_{i} \leq 20\);

对于 \(50 \%\) 的评测用例, \(n \leq 500,1 \leq x_{i}<y_{i} \leq 200\);

对于所有评测用例, \(1 \leq n \leq 10^5,1 \leq x_{i}<y_{i} \leq 10^{9}\)

蓝桥杯 2022 省赛 A 组 E 题。

解题思路

\(f_i\)表示从第\(i\)层爬到第\(n\)层的时间期望。
容易得到:

\[f_n=0 \]

\[f_{n-1}=(1-p_n)*f_n+p_n*f_0+1 \]

\[f_{n-2}=(1-p_{n-1})*f_{n-1}+p_{n-1}*f_0+1 \]

\[...... \]

上面两个式子可以改写成:

\[f_{n-1}=a_{n-1}*f_0+b_{n-1} \]

\[f_{n-2}=a_{n-2}*f_0+b_{n-2} \]

由于\(f_n=0\),可以得到\(a_{n-1}=p_n\)\(b_{n-1}=1\)
下面来看下如何由\(a_{n-1},b_{n-1}\)推出\(a_{n-2},b_{n-2}\)

\[f_{n-2}=(1-p_{n-1})*(a_{n-1}*f_0+b_{n-1})+p_{n-1}*f_0+1 \]

\[f_{n-2}=(a_{n-1}*(1-p_{n-1})+p_{n-1})*f_0+(1-p_{n-1})*b_{n-1}+1 \]

即:

\[a_{n-2}=a_{n-1}*(1-p_{n-1})+p_{n-1} \]

\[b_{n-2}=(1-p_{n-1})*b_{n-1}+1 \]

最终有:

\[f_0=a_1*f_0+b_1 \]

只需求得\(a_1\)\(b_1\)即可。

参考代码

#include <bits/stdc++.h>
using namespace std;
const int mod = 998244353;
#define ll long long
const int N = 1e5 + 10;
ll x[N], y[N], p[N];
ll ksm(ll a, ll b)
{
    ll ans = 1;
    ll base = a;
    while (b)
    {
        if (b & 1)
        {
            ans *= base;
            ans %= mod;
        }
        base *= base;
        base %= mod;
        b >>= 1;
    }
    return ans;
}
int main()
{
    int n;
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; ++i)
    {
        cin >> x[i] >> y[i];
        p[i] = x[i] * ksm(y[i], mod - 2) % mod;
    }
    ll a = 0, b = 0;
    for (int i = n; i >= 1; --i)
    {
        a = ((a * (1 - p[i]) + p[i]) % mod + mod) % mod;
        b = (((1 - p[i] )* b + 1) % mod + mod) % mod;
    }
    cout << b * ksm(1 - a + mod, mod - 2) % mod;
    return 0;
}