題面c++
咱們能夠把到每一個點的指望步數算出來取max?可是直接算顯然是不行的spa
那就能夠用Min-Max來容斥一下code
設\(g_{s}\)是從x到s中任意一個點的最小步數get
設\(f_{s}\)是從x到s中任意一個點的最大步數input
而後就能夠的獲得it
\(f_{s}=\sum_{t\subseteq s}(-1)^{|t|+1}g_t\)io
而後考慮g怎麼求ast
設\(p_i\)是i點到任意一個子集中的點的最小步數function
有\(p_u=\frac{1}{du_u}(1+p_{fa_u})+\frac{1}{du_u}\sum_{v\in child_u}(p_v+1)\)class
而後咱們令\(p_u=a_up_{fa_u}+b_u\)
很顯然有\(p_u=\frac{1}{du_u}\sum(a_vf_u+b_v+1)+\frac{1}{du_u}(p_{fa_u})\)
而後移項能夠獲得\(a_u=\frac{1}{du_u-\sum a_v},b_u=\frac{\sum(b_v+1)+1}{du_u-\sum a_v}\)
而後由於x是根沒有父親,因此\(g_{s}=(bitcnt(s) \& 1)?b_u:-b_u\)
而後就能夠用子集前綴和進行累加了
最後直接輸出答案就能夠了
#include <bits/stdc++.h> using namespace std; const int Mod = 998244353; const int N = 20; int n, m, x; int a[N], b[N], du[N]; int f[1 << N]; vector<int> g[N]; int main() { #ifdef dream_maker freopen("input.txt", "r", stdin); #endif function<int(int a, int b)> add = [&](int a, int b) { return (a += b) >= Mod ? a - Mod : a; }; function<int(int a, int b)> sub = [&](int a, int b) { return (a -= b) < 0 ? a + Mod : a; }; function<int(int a, int b)> mul = [&](int a, int b) { return (long long) a * b % Mod; }; function<int(int a, int b)> fast_pow = [&](int a, int b) { int res = 1; for (; b; b >>= 1, a = mul(a, a)) if (b & 1) res = mul(res, a); return res; }; function<int(int a)> bitcnt = [&](int a) { int res = 0; for (; a; a >>= 1) if (a & 1) ++res; return res; }; function<void(int u, int fa, int s)> dfs = [&](int u, int fa, int s) { if ((s >> (u - 1)) & 1) return; a[u] = du[u], b[u] = (u == x) ? 0 : 1; // x不用向fa走的1 for (auto v : g[u]) { if (v == fa) continue; dfs(v, u, s); a[u] = sub(a[u], a[v]); b[u] = add(b[u], b[v] + 1); } a[u] = fast_pow(a[u], Mod - 2); b[u] = mul(b[u], a[u]); }; scanf("%d %d %d", &n, &m, &x); for (int i = 1; i < n; i++) { int u, v; scanf("%d %d", &u, &v); g[u].push_back(v); g[v].push_back(u); ++du[u], ++du[v]; } int up = (1 << n) - 1; for (int s = 1; s <= up; s++) { for (int i = 1; i <= n; i++) a[i] = b[i] = 0; dfs(x, 0, s); f[s] = (bitcnt(s) & 1) ? b[x] : (Mod - b[x]) % Mod; } f[0] = 0; for (int i = 1; i <= n; i++) { // 這個循環在外面 for (int s = 1; s <= up; s++) { if ((s >> (i - 1)) & 1) { f[s] = add(f[s], f[s ^ (1 << (i - 1))]); } } } while (m--) { int num, cur, s = 0; scanf("%d", &num); while (num--) { scanf("%d", &cur); s |= 1 << (cur - 1); } printf("%d\n", f[s]); } return 0; }