题解:P17408 【MX-X31-T4】「FAOI-R14」单人游戏
hetao1733837 · · 题解
我们把
-
- 反之,我们发现,期望可以表示为
E_i=1+\dfrac{sz_i}{n-1}\times E_i+\dfrac{1-p}{n-1}\sum\limits_{j\neq i}^{}{sz_j\times E_j}
怎么理解这个式子呢?
首先,我们另
对于
对于
这个式子太丑了(明明很优美),我们考虑化简。
设
不妨移项,得出:
合并同类项得:
将括号内的化简,可得:
将括号两边同时乘上
不妨设
继续化简,得:
此时,我们发现:
不妨令
可以解得:
则反代原式:
我们终于得出了式子!!!
发现里面全都是常数项,就可以直接做了!
至于实现,倍增处理,快速确定每个点所处的连通块的大小,然后,判断具体位置,套公式即可。
正解
#include <bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;
const int N = 100005;
int n, pp, q;
vector<int> e[N];
int sz[N];
int dfn[N], rk[N], tot;
int fa[N];
int de[N];
int f[N][22];
int deg[N];
int inv_son[N], inv_fa[N];
int S[N];
int INV[N];
int qpow(int a, int b){
int res = 1;
a = (a % mod + mod) % mod;
while (b){
if (b & 1)
res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
void dfs(int u, int pa){
sz[u] = 1;
f[u][0] = pa;
fa[u] = pa;
de[u] = de[pa] + 1;
dfn[u] = ++tot;
rk[tot] = u;
for (auto v : e[u]){
if (v == pa)
continue;
dfs(v, u);
sz[u] += sz[v];
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> pp >> q;
int p = pp % mod * qpow(100, mod - 2) % mod;
for (int i = 1, u, v; i < n; i++){
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
deg[u]++;
deg[v]++;
}
dfs(1, 0);
for (int i = 1; i <= 20; i++)
for (int u = 1; u <= n; u++)
f[u][i] = f[f[u][i - 1]][i - 1];
for (int i = 2; i <= n; i++){
int den = ((n - 1) - p * sz[i] % mod + mod) % mod;
inv_son[i] = qpow(den, mod - 2);
S[f[i][0]] = (S[f[i][0]] + sz[i] % mod * inv_son[i]) % mod;
}
for (int i = 1; i <= n; i++){
int tmp1 = S[i];
if (f[i][0]){
int tmp2 = n - sz[i];
int den = ((n - 1) - p * tmp2 % mod + mod) % mod;
inv_fa[i] = qpow(den, mod - 2);
tmp1 = (tmp1 + tmp2 % mod * inv_fa[i]) % mod;
}
int D = (1 - (1 - p + mod) % mod * tmp1 % mod + mod) % mod;
INV[i] = qpow(D, mod - 2);
}
for (int cs = 1, x, u; cs <= q; cs++){
cin >> x >> u;
if (deg[u] == 1){
cout << -1 << "\n";
continue;
}
int inv;
if (dfn[u] <= dfn[x] && dfn[x] <= dfn[u] + sz[u] - 1){
int delta = de[x] - de[u] - 1;
int anc = x;
for (int j = 20; j >= 0; j--)
if ((delta >> j) & 1)
anc = f[anc][j];
inv = inv_son[anc];
}
else{
inv = inv_fa[u];
}
cout << (n - 1) % mod * inv % mod * INV[u] % mod << "\n";
}
return 0;
}