Luogu P5643 [PKUWC2018]随机游走
Luogu P5643 [PKUWC2018]随机游走
题目要求的是点集 \(S\) 内所有点被经过的期望步数,这个东西直接做比较难;可以考虑使用 期望意义下的min-max容斥 将其转化为到达点集 \(S\) 内第一个点的期望步数。设 \(h_{S}\) 表示从起点 \(X\) 开始到达点集 \(S\) 内第一个点带期望步数,则由期望意义下的min-max容斥知 \(\mathrm{Ans}=\sum\limits_{T\subseteq S}(-1)^{|T|+1}h_T\)。
设 \(f_{S,u}\) 为从点 \(u\) 出发到达点集 \(S\) 内第一个点的期望步数。设 \(\deg_u\) 为点 \(u\) 的度数,则有
直接使用高斯消元是 \(\mathcal O(n^3)\) 的,处理 \(f_{S,u}\) 的时间复杂度就是 \(\mathcal O(2^nn^3)\) 的,这显然不行。
考虑优化。假设我们对于给定 \(S\) 已经求出了所有的 \(f_{S,u}\),容易发现 \(f_{S,u}\) 可以表示为 \(k_uf_{S,\operatorname{fa}_u}+b_u\) 的形式。带入上式,则有
令 \(K_u=\sum\limits_{v\in \operatorname{ch}_u}k_v,\,B_u=\sum\limits_{v\in\operatorname{ch}_u}b_v\),解上述方程,有
即有 \(k_x=\dfrac 1{\deg_x-K_x},\,b_x=\dfrac {\deg_x+B_x}{\deg_x-K_x}\)。于是我们可以直接树形DP求出 \(k_x,b_x\) 的值,进而求出 \(f_{S,x}\) 的值。树形DP的时间复杂度是 \(\mathcal O(n)\) 的,这一部分的总时间复杂度就被降到了 \(\mathcal O(2^nn)\) 了。
考虑如何处理询问。预处理时对 \(f'_S=(-1)^{|S|+1}f_{S,X}\) 做高维前缀和,查询时直接 \(\mathcal O(1)\) 查询即可。总时间复杂度为 \(\mathcal O(2^nn\log V+q)\),其中 \(\log V\) 是处理逆元的复杂度。
参考代码
#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
浙公网安备 33010602011771号