题解 AT2705 【[AGC019F] Yes or No】
在博客园食用更佳:https://www.cnblogs.com/PinkRabbit/p/AGC019.html。
我们将
最佳策略是:此时已知 Yes 有
我们用横坐标表示
可以发现,此时若折线向左,就相当于是本题答案为 Yes,向下则本题答案为 No。
同时,图中还有一条线:被方程
如果此时位置不在斜线上,则我们的最佳策略指出,将会回答更靠近斜线的答案。否则不妨回答 Yes。
如果回答的答案恰好与折线的走势相同,则相当于答对了一题,否则答错。
但是无论如何我们的位置,都会同折线一起前进一步,可能更靠近斜线也可能更远离斜线。
那么此时就等价于:折线经过的红色线段数量,就是我们会在这条折线对应的答案序列上产生的得分。
我们对所有的折线,将这个数值求和,然后除以
折线经过的红色线段数量如何统计呢?我们不妨假设
此时如果折线到达了斜线的上方,我们强行把到达斜线上方的那一部分,给折回来,折到斜线下方。
这样一变换,折线在斜线上方的部分,经过的红色线段的数量,可以发现大部分都是没变化的。
但这只是除了刚好从斜线上往左走的那些,也就是,这样折回来,损失了刚好从斜线上往左走的那一部分。
我们先不考虑那些损失,对于从未到达斜线上方的折线,显然,经过的红色线段数量恰好为
那么我们只需统计刚好从斜线上往左走的期望次数。
显然只需要对斜线上的每个点,统计折线经过它的概率,乘上
最终答案就是
#include <cstdio>
#include <algorithm>
typedef long long LL;
const int Mod = 998244353, Inv2 = (Mod + 1) / 2;
const int MN = 1000005;
inline int qPow(int b, int e) {
int a = 1;
for (; e; e >>= 1, b = (LL)b * b % Mod)
if (e & 1) a = (LL)a * b % Mod;
return a;
}
inline int gInv(int b) { return qPow(b, Mod - 2); }
int Fac[MN], iFac[MN];
inline void Init(int N) {
Fac[0] = 1;
for (int i = 1; i <= N; ++i) Fac[i] = (LL)Fac[i - 1] * i % Mod;
iFac[N] = gInv(Fac[N]);
for (int i = N; i >= 1; --i) iFac[i - 1] = (LL)iFac[i] * i % Mod;
}
inline int Binom(int N, int M) {
if (M < 0 || M > N) return 0;
return (LL)Fac[N] * iFac[M] % Mod * iFac[N - M] % Mod;
}
inline int Calc(int N, int M) {
return Binom(N + M, N);
}
int N, M;
int main() {
scanf("%d%d", &N, &M);
if (N < M) std::swap(N, M);
Init(N + M);
int Ans = 0;
for (int i = 1; i <= M; ++i) Ans = (Ans + (LL)Calc(i, i) * Calc(N - i, M - i)) % Mod;
Ans = (LL)Ans * gInv(Calc(N, M)) % Mod;
printf("%lld\n", (N + (LL)Ans * Inv2) % Mod);
return 0;
}