概述
题意
- 给你一个 n n n个点的树,询问从 s s s号点出发,每次等概率选择一个相邻的点移动,求把集合 S S S每个点至少访问一次的期望步数。
首先我们很自然设
f
[
u
]
[
S
]
f[u][S]
f[u][S]为从
u
u
u号点出发访问
S
S
S集合至少一次的期望步数,那么我们可以写出DP方程:
f
[
u
]
[
S
]
=
1
d
e
[
u
]
∑
e
d
g
e
(
u
,
v
)
(
f
[
v
]
[
S
]
+
1
)
(
u
∉
S
)
f
[
u
]
[
S
]
=
1
d
e
[
u
]
∑
e
d
g
e
(
u
,
v
)
(
f
[
v
]
[
S
−
u
]
+
1
)
(
u
∈
S
)
f[u][S]=frac{1}{de[u]}sum_{edge(u,v)}(f[v][S]+1)(unotin S)\ f[u][S]=frac{1}{de[u]}sum_{edge(u,v)}(f[v][S-u]+1)(uin S)
f[u][S]=de[u]1edge(u,v)∑(f[v][S]+1)(u∈/S)f[u][S]=de[u]1edge(u,v)∑(f[v][S−u]+1)(u∈S)
我们发现每个集合 S S S要么从比它小的集合转移来,要么从它自己转移来,这个东西你从小到大枚举集合套高斯消元求解的话就是 O ( 2 n n 3 ) O(2^nn^3) O(2nn3)的,但这个复杂度显然不靠谱,考虑优化。方便起见,以下用 f [ u ] f[u] f[u]表示 f [ u ] [ S ] f[u][S] f[u][S]。
考虑一类期望DP的套路,我们把
f
[
u
]
f[u]
f[u]写成
A
u
×
f
[
f
a
[
u
]
]
+
B
u
A_utimes f[fa[u]]+B_u
Au×f[fa[u]]+Bu的形式。先特判
u
=
S
u=S
u=S的情况,这个时候很显然
A
u
=
B
u
=
0
A_u=B_u=0
Au=Bu=0,剩下的情况我们代回那个方程去解系数:
f
[
u
]
=
f
[
f
a
[
u
]
]
d
e
[
u
]
+
∑
u
=
f
a
[
v
]
f
[
v
]
[
S
]
d
e
[
u
]
+
1
(
u
∉
S
)
f
[
u
]
=
f
[
f
a
[
u
]
]
d
e
[
u
]
+
∑
u
=
f
a
[
v
]
A
v
f
[
u
]
+
B
v
d
e
[
u
]
+
1
(
u
∉
S
)
f
[
u
]
d
e
[
u
]
=
f
[
f
a
[
u
]
]
+
∑
u
=
f
a
[
v
]
A
v
f
[
u
]
+
B
v
+
1
(
u
∉
S
)
f
[
u
]
=
1
d
e
[
u
]
−
∑
A
v
×
f
[
f
a
[
u
]
]
+
∑
B
v
+
d
e
[
u
]
d
e
[
u
]
−
∑
A
v
(
u
∉
S
)
f[u]=frac{f[fa[u]]}{de[u]}+sum_{u=fa[v]}frac{f[v][S]}{de[u]}+1(unotin S)\ f[u]=frac{f[fa[u]]}{de[u]}+sum_{u=fa[v]}frac{A_vf[u]+B_v}{de[u]}+1(unotin S)\ f[u]de[u]=f[fa[u]]+sum_{u=fa[v]}A_vf[u]+B_v+1(unotin S)\ f[u]=frac{1}{de[u]-sum A_v}times f[fa[u]]+frac{sum{B_v+de[u]}}{de[u]-sum A_v}(unotin S)
f[u]=de[u]f[fa[u]]+u=fa[v]∑de[u]f[v][S]+1(u∈/S)f[u]=de[u]f[fa[u]]+u=fa[v]∑de[u]Avf[u]+Bv+1(u∈/S)f[u]de[u]=f[fa[u]]+u=fa[v]∑Avf[u]+Bv+1(u∈/S)f[u]=de[u]−∑Av1×f[fa[u]]+de[u]−∑Av∑Bv+de[u](u∈/S)
u
∉
S
unotin S
u∈/S的情况更简单,因为它转移用到的信息都是算出来的,那么直接令:
A
u
=
0
,
B
u
=
1
d
e
[
u
]
∑
e
d
g
e
(
u
,
v
)
(
f
[
v
]
[
S
−
u
]
+
1
)
A_u=0,B_u=frac{1}{de[u]}sum_{edge(u,v)}(f[v][S-u]+1)
Au=0,Bu=de[u]1edge(u,v)∑(f[v][S−u]+1)
我们最后往回代计算DP值就好了,复杂度 O ( n 2 n ) O(n2^n) O(n2n)。
#include <bits/stdc++.h>
#define pb push_back
#define SZ(x) ((int)x.size())
#define For(i, a, b) for (int i = a; i <= b; ++ i)
using namespace std;
const int N = 18 + 3;
const int M = 1 << 18;
const int mod = 998244353;
vector<int> G[N];
int f[N][M], A[N][M], B[N][M], de[N];
int qpow(int a, int x) {
int ret = 1;
while (x) {
if (x & 1) ret = 1ll * ret * a % mod;
x >>= 1, a = 1ll * a * a % mod;
}
return ret;
}
void dfs(int u, int dad, int S) {
for (auto v : G[u]) if (v ^ dad) dfs(v, u, S);
if ((1 << (u - 1)) & S) {
A[u][S] = 0;
if (__builtin_popcount(S) == 1)
return (void)(B[u][S] = 0);
for (auto v : G[u])
(B[u][S] += f[v][S ^ (1 << (u - 1))] + 1) %= mod;
B[u][S] = 1ll * B[u][S] * qpow(de[u], mod - 2) % mod;
} else {
A[u][S] = B[u][S] = de[u];
for (auto v : G[u]) if (v ^ dad) {
(A[u][S] += mod - A[v][S]) %= mod;
(B[u][S] += B[v][S]) %= mod;
}
A[u][S] = qpow(A[u][S], mod - 2);
B[u][S] = 1ll * B[u][S] * A[u][S] % mod;
}
}
void DFS(int u, int dad, int S) {
f[u][S] = (1ll * A[u][S] * f[dad][S] % mod + B[u][S]) % mod;
for (auto v : G[u]) if (v ^ dad) DFS(v, u, S);
}
int main() {
freopen("2542.in", "r", stdin);
freopen("2542.out", "w", stdout);
int x, y, z, n, q, s;
scanf("%d%d%d", &n, &q, &s);
For(i, 2, n) {
scanf("%d%d", &x, &y);
G[x].pb(y), G[y].pb(x);
}
int all = 1 << n;
For(i, 1, n)
de[i] = SZ(G[i]);
For(i, 1, all - 1) {
dfs(1, 0, i);
DFS(1, 0, i);
}
For(i, 1, q) {
scanf("%d", &x), z = 0;
For(j, 1, x) {
scanf("%d", &y);
z |= 1 << (y - 1);
}
printf("%dn", f[s][z]);
}
return 0;
}
最后
以上就是彩色棒棒糖为你收集整理的[LOJ2542] 「PKUWC2018」随机游走(期望DP)的全部内容,希望文章能够帮你解决[LOJ2542] 「PKUWC2018」随机游走(期望DP)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复