贴的 年的题解,今天发现洛谷搬这个题了就发出来了()
Hint
考虑对于每一个 的值,将 按照奇偶性分类?
Solution
首先可以暴力搜索算出每一个 的值,这是简单的,可以通过 的部分。
然后有一个简单的 dp 思路:设 表示当前在 的概率,可以在 的时间复杂度内解决(其实是 的)。通过 的分数。
考虑先对于给定的 求 。若存在一条路径从 经过若干个结点走到了 (),则必然可以找到一条和这个路径每一步方向均相反的路径。考虑计算这个人分别走这两条路径概率的比值。容易发现,若当前在点 (), 的变化 已知,则从 走到 的概率和从 走到 的概率相同。若 ,则若 ,则从 走到 的概率为 ,从 走到 的概率为 。
显而易见的是只需要分别计数两条路径中 时不同 出现的次数即可。考虑到这两条路径因为完全对称,所以 出现的次数必然相同。考虑定义 时 则会让 移动到 轴上方(简记为“上行”), 则会让 移动到 轴下方(简记为“下行”)。因为最终 位于 轴上方, 位于 轴下方,所以可以简单证明 中上行操作比下行操作多 , 中上行操作比下行操作少 。经过这通分析之后可以发现最终移动到 的概率是移动到 概率的 。
令 表示移动到 的概率,则有 。
于是考虑对 做奇偶分析。因为每一次移动操作 的奇偶性都会发生变化,所以说 的奇偶性不会变化,均为偶数。因此若 ,则经过 次操作之后人一定不会移动到 位置。此时答案即为 ,有 ,又因为 ,所以有 。于是这一类情况就被解决掉了。
剩下 的情况。同样的还有 ,但是此时 不成立。所以考虑计算出 的答案,有 成立,联立上面的方程式就可以求出 的值。问题变为求 。显然可以 暴力 dp 求解,但是这和上面的做法没有本质的区别。
对于 ,对于 的情况,由 转移向 ,概率为 和概率为 的边出现的次数是相同的。关键就在于 的时候,走了多少条 的概率为 的边。这里枚举走了 条这样的边,则简单推导后可以发现此时经过了 条概率为 的边, 条概率为 的边。其中 。
也就是说,若 时走了 条 即概率为 的边,则对于每一条这样的路径,人这么走的概率都为 。新的问题是对每一个 计数有多少条这样的路径,可以简单组合计数得到路径的数目为 。这里认为 时 。为了方便记录这个值为 。
因此答案即为 ()。
直接暴力对每一个 ()计数并求和,时间复杂度为 (其实是 的,相比前面确实有了优化)。
继续优化。考虑到 其实是一个很复杂的,对于每个 都需要 计算的表达式,把她再次展开,得到 。考虑到 和 为倍数关系,因此将 拆分为 和 ,得到 ,即 。其中前面的 是容易计算的,而后半部分的 则可以被拆为 和 两个部分。
于是考虑拆分式子,并构造下面的两个函数:,。则经过推导可以得到下面的递推式:
初始条件手算可以得到 。
很显然这两个式子做差之后随便算一下就可以得到 了,这一步是容易的。剩下的只需要预处理幂次和组合数,显然可以通过线性求逆元等方式做到 。于是总时间复杂度为 ,可以通过该题。
Code
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 10000100, mod = 998244353;
int n, fac[N], inv[N], ifac[N], pw2[N], pw3[N], f[N], g[N];
int binom(int x, int y) {
if (y < 0 || x < y) return 0;
return fac[x] * ifac[y] % mod * ifac[x - y] % mod;
}
signed main() {
cin.tie(0)->sync_with_stdio(0);
cin >> n;
for (int i = 0; i < 2; ++i) fac[i] = inv[i] = ifac[i] = 1;
for (int i = 2; i < N; ++i) {
fac[i] = fac[i - 1] * i % mod;
inv[i] = mod - inv[mod % i] * (mod / i) % mod;
ifac[i] = ifac[i - 1] * inv[i] % mod;
}
pw2[0] = pw3[0] = 1;
for (int i = 1; i < N; ++i) {
pw2[i] = pw2[i - 1] * 2 % mod;
pw3[i] = pw3[i - 1] * 3 % mod;
}
f[0] = 1, g[0] = 0;
for (int i = 0; i + 2 < N; i += 2) {
f[i + 2] = (f[i] * 9 % mod - binom(i, i / 2) * pw2[i >> 1] % mod + binom(i, i / 2 - 1) * pw2[i / 2 + 1] % mod + mod) % mod;
g[i + 2] = (g[i] * 9 % mod - binom(i, i / 2 + 1) * pw2[i >> 1] % mod + binom(i, i / 2) * pw2[i / 2 + 1] % mod + mod) % mod;
}
int i3 = inv[3], s = 0;
for (int i = 1; i <= n; ++i) {
int qz = (1'000'000'000'000'000'000 / i) % mod;
if (i & 1) s = (s + pw3[i - 1] * qz % mod) % mod;
else s = (s + (g[i] - f[i] + mod + pw3[i]) * i3 % mod * qz % mod) % mod;
}
cout << s << '\n';
return 0;
}
喜欢的话,留下你的评论吧~