ACGO巅峰赛#22+题解
2025-06-23 14:43:20
发布于:河北
36阅读
0回复
0点赞
解题思路
设树的节点数为 ,对任意根 ,定义:
- :以 为根的子树大小;
- :从 出发随机 BFS 其子树的方案数。
算法分三步:
-
预处理
- 预计算阶乘 和逆元阶乘 ()。
-
初始 DFS(根为 0)
自底向上计算 和 :
等价形式(化简后):
-
重根 DP(Rerooting)
沿边 转移根时,分两步更新:- 摘除子树 (从 侧):
- 接入子树 (到 侧):
通过一次后序遍历和一次前序遍历, 时间内完成所有根的 计算。
- 摘除子树 (从 侧):
输出:对每个节点 ,输出 。
复杂度:时间 ,空间 。
代码解释
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1000005;
const int MOD = 998244353;
int n;
vector<int> adj[MAXN];
long long fact[MAXN], invfact[MAXN];
long long qpow(long long a, long long b) {
long long res=1;
while(b) {
if(b&1) res=res*a%MOD;
a=a*a%MOD;
b>>=1;
}
return res;
}
long long comb(int a,int b) {
if(b > a || b < 0) return 0;
return fact[a]*invfact[b]%MOD*invfact[a-b]%MOD;
}
long long multinomial(int total, const vector<int>& parts) {
long long res = fact[total];
for(auto x: parts) res = res * invfact[x] % MOD;
return res;
}
int sz[MAXN];
long long f[MAXN];
void dfs1(int u, int fa) {
sz[u] = 1;
vector<int> parts;
long long res=1;
for(auto v : adj[u]) {
if(v == fa) continue;
dfs1(v,u);
sz[u] += sz[v];
parts.push_back(sz[v]);
res = res * f[v] % MOD;
}
if(!parts.empty()) res = res * multinomial(sz[u]-1, parts) % MOD;
f[u] = res;
}
long long ans[MAXN];
void reroot(int u, int fa) {
ans[u] = f[u];
for(auto v : adj[u]) {
if(v == fa) continue;
int su = sz[u], sv = sz[v];
long long fu = f[u], fv = f[v];
f[u] = f[u] * qpow(f[v], MOD-2) % MOD;
f[u] = f[u] * fact[su - sv - 1] % MOD;
f[u] = f[u] * invfact[su - 1] % MOD;
f[u] = f[u] * fact[sv] % MOD;
sz[u] = su - sv;
f[v] = f[v] * f[u] % MOD;
f[v] = f[v] * fact[sv + sz[u] - 1] % MOD;
f[v] = f[v] * invfact[sv - 1] % MOD;
f[v] = f[v] * invfact[sz[u]] % MOD;
sz[v] = sv + sz[u];
reroot(v, u);
f[u] = fu; f[v] = fv;
sz[u] = su; sz[v] = sv;
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for(int i=1;i<n;i++){
int u,v; cin >> u >> v; u--; v--;
adj[u].push_back(v);
adj[v].push_back(u);
}
fact[0] = invfact[0] = 1;
for(int i=1;i<=n;i++) fact[i] = fact[i-1]*i%MOD;
invfact[n] = qpow(fact[n], MOD-2);
for(int i=n-1;i>=1;i--) invfact[i] = invfact[i+1]*(i+1)%MOD;
dfs1(0,-1);
reroot(0,-1);
for(int i=0;i<n;i++) cout << ans[i] << "\n";
return 0;
}
这里空空如也
有帮助,赞一个