Luogu P5643 [PKUWC2018]随机游走
Luogu P5643 [PKUWC2018]随机游走
题目要求的是点集 内所有点被经过的期望步数,这个东西直接做比较难;可以考虑使用 期望意义下的min-max容斥 将其转化为到达点集 内第一个点的期望步数。设 表示从起点 开始到达点集 内第一个点带期望步数,则由期望意义下的min-max容斥知 。
设 为从点 出发到达点集 内第一个点的期望步数。设 为点 的度数,则有
直接使用高斯消元是 的,处理 的时间复杂度就是 的,这显然不行。
考虑优化。假设我们对于给定 已经求出了所有的 ,容易发现 可以表示为 的形式。带入上式,则有
令 ,解上述方程,有
即有 。于是我们可以直接树形DP求出 的值,进而求出 的值。树形DP的时间复杂度是 的,这一部分的总时间复杂度就被降到了 了。
考虑如何处理询问。预处理时对 做高维前缀和,查询时直接 查询即可。总时间复杂度为 ,其中 是处理逆元的复杂度。
参考代码
#include <bits/stdc++.h>
using namespace std;
static constexpr int mod = 998244353;
inline int add(int x, int y) { return x += y - mod, x + (x >> 31 & mod); }
inline int sub(int x, int y) { return x -= y, x + (x >> 31 & mod); }
inline int mul(int x, int y) { return (int64_t)x * y % mod; }
inline void add_eq(int &x, int y) { x += y - mod, x += (x >> 31 & mod); }
inline void sub_eq(int &x, int y) { x -= y, x += (x >> 31 & mod); }
inline void mul_eq(int &x, int y) { x = (int64_t)x * y % mod; }
int qpow(int x, int y) { int r = 1; for (; y; y >>= 1, mul_eq(x, x)) if (y & 1) mul_eq(r, x); return r; }
static constexpr int N = 18;
int n, Q, X, en, head[N], deg[N];
struct Edge { int to, nxt; } e[N * 2];
void add_edge(int u, int v) {
e[++en] = (Edge){v, head[u]}, head[u] = en;
e[++en] = (Edge){u, head[v]}, head[v] = en;
++deg[u], ++deg[v];
} // add_edge
int f[1 << N], K[N], B[N];
void dfs(const int &S, int u, int fa) {
if (S >> u & 1) return K[u] = B[u] = 0, void();
int ks = 0, bs = 0;
for (int i = head[u], v; i; i = e[i].nxt)
if ((v = e[i].to) != fa)
dfs(S, v, u), add_eq(ks, K[v]), add_eq(bs, B[v]);
K[u] = qpow(sub(deg[u], ks), mod - 2);
B[u] = mul(K[u], add(deg[u], bs));
} // dfs
int main(void) {
scanf("%d%d%d", &n, &Q, &X), --X;
for (int i = 1, u, v; i < n; ++i)
scanf("%d%d", &u, &v), --u, --v, add_edge(u, v);
for (int s = 1; s < (1 << n); ++s)
dfs(s, X, -1), f[s] = (__builtin_parity(s) ? B[X] : sub(0, B[X]));
for (int i = 0; i < n; ++i)
for (int s = 0; s < (1 << n); ++s)
if (s >> i & 1) add_eq(f[s], f[s ^ (1 << i)]);
while (Q--) {
int m, s = 0, x; scanf("%d", &m);
while (m--) scanf("%d", &x), --x, s |= (1 << x);
printf("%d\n", f[s]);
}
exit(EXIT_SUCCESS);
} // main
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】