题目 | Critical Hit
Denso Create Programming Contest 2022 Winter(AtCoder Beginner Contest 280)
E - Critical Hit
https://atcoder.jp/contests/abc280/tasks/abc280_e
Time Limit: 2 sec / Memory Limit: 1024 MB
Score : $500$ points
Problem Statement
There is a monster with initial stamina $N$.
Takahashi repeatedly attacks the monster while the monster's stamina remains $1$ or greater.
An attack by Takahashi reduces the monster's stamina by $2$ with probability $\frac{P}{100}$ and by $1$ with probability $1-\frac{P}{100}$.
Find the expected value, modulo $998244353$ (see Notes), of the number of attacks before the monster's stamina becomes $0$ or less.
Notes
We can prove that the sought expected value is always a finite rational number. Moreover, under the Constraints of this problem, when the value is represented as $\frac{P}{Q}$ by two coprime integers $P$ and $Q$, we can show that there exists a unique integer $R$ such that $R \times Q \equiv P\pmod{998244353}$ and $0 \leq R \lt 998244353$. Print such $R$.
Constraints
- $1 \leq N \leq 2\times 10^5$
- $0 \leq P \leq 100$
- All values in the input are integers.
Input
The input is given from Standard Input in the following format:
$N$ $P$
Output
Find the expected value, modulo $998244353$, of the number of Takahashi's attacks.
Sample Input 1
3 10
Sample Output 1
229596204
An attack by Takahashi reduces the monster's stamina by $2$ with probability $\frac{10}{100}=\frac{1}{10}$ and by $1$ with probability $\frac{100-10}{100}=\frac{9}{10}$.
- The monster's initial stamina is $3$.
- After the first attack, the monster's stamina is $2$ with probability $\frac{9}{10}$ and $1$ with probability $\frac{1}{10}$.
- After the second attack, the monster's stamina is $1$ with probability $\frac{81}{100}$, $0$ with probability $\frac{18}{100}$, and $-1$ with probability $\frac{1}{100}$. With probability $\frac{18}{100}+\frac{1}{100}=\frac{19}{100}$, the stamina becomes $0$ or less, and Takahashi stops attacking after two attacks.
- If the stamina remains $1$ after two attacks, the monster's stamina always becomes $0$ or less by the third attack, so he stops attacking after three attacks.
Therefore, the expected value is $2\times \frac{19}{100}+3\times\left(1-\frac{19}{100}\right)=\frac{281}{100}$. Since $229596204 \times 100 \equiv 281\pmod{998244353}$, print $229596204$.
Sample Input 2
5 100
Sample Output 2
3
Takahashi's attack always reduces the monster's stamina by $2$. After the second attack, the stamina remains $5-2\times 2=1$, so the third one is required.
Sample Input 3
280 59
Sample Output 3
567484387
题解
题面分析
该题为一个非常基础的 DP + 模逆元题,只不过题面的 Notes 小节有点坑人,需要重点关注下(我就因为这被害了)
首先 Notes 中的变量 $P$ 与输入数据的变量 $P$ 是两个东西,不要把这俩当成同一个变量了,否则题目就看不明白了。
其次,要我们输出满足 $R \times Q \equiv P\pmod{998244353}$ 的 $R$ 是个啥东西。这个等式其实不要想复杂了,其实就是 $\frac{P}{Q}$,其中将除法运算改成用模逆元乘法运算即可。
分析后,问题就清晰了,题目就是让我们使用模逆元计算这个期望值罢了。
动态规划
我们约定 $dp_i:=$ 造成伤害 $i$ 需要的步数的期望。
易得 $dp_0=0$,$dp_1=1$(每一步至少造成 $1$ 点伤害,因此只需 $1$ 步)
接下来的递推方式为:
$$ \begin{align} dp_i&=(dp_{i-2}+1)\cdot\frac{P}{100}+(dp_{i-1}+1)\cdot(1-\frac{P}{100})\\ &=dp_{i-2}\cdot\frac{P}{100}+dp_{i-1}\cdot(1-\frac{P}{100})+1 \end{align} $$
具体解释,要达成 $i$ 点伤害,有两种情况:
- 前面达成了 $i-2$ 点伤害,最后一步达成了 $2$ 点伤害,期望为 $(dp_{i-2}+1)\cdot\frac{P}{100}$
- 前面达成了 $i-1$ 点伤害,最后一步达成了 $1$ 点伤害,期望为 $(dp_{i-1}+1)\cdot(1-\frac{P}{100})$
模逆元
(关于模逆元:https://io.zouht.com/13.html)
原式转化为:
$$ dp_i=dp_{i-2}\cdot P\cdot\mathrm{inv}(100)+dp_{i-1}\cdot(1-P\cdot\mathrm{inv}(100))+1 $$
可见只用的找 $100$ 的模逆元,完全可以直接算出来它的值为 $828542813$.
代码
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
const ll MOD = 998244353;
/* ll fastpow(ll a, ll b)
{
a %= MOD;
ll ans = 1;
while (b)
{
if (b % 2 == 1)
ans = ans * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return ans;
}
inline ll inv(ll x)
{
return fastpow(x, MOD - 2);
} */
const ll MAXN = 2e5 + 10;
ll dp[MAXN];
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
ll N, P;
cin >> N >> P;
// ll inv100 = inv(100);
ll inv100 = 828542813;
dp[1] = 1;
for (int i = 2; i <= N; i++)
{
dp[i] = P * inv100 % MOD * dp[i - 2] % MOD +
(1 - (P * inv100 % MOD) + MOD) % MOD * dp[i - 1] % MOD + 1;
dp[i] %= MOD;
}
cout << dp[N] << endl;
return 0;
}
本文采用 CC BY-SA 4.0 许可,本文 Markdown 源码:Haotian-BiJi