题解:P6383 『MdOI R2』Resurrection

posted on 2024-10-15 13:58:51 | under | source

呜呜呜看不懂题解所以来写一篇。

根据题意,以 \(n\) 为根的树满足 \(u\le fa\),那么建图的过程可以视作:选取 \((u,fa)\) 删去,从 \(fa\) 开始往上走找到第一个满足父边已被删除的点 \(p\),建边 \((u,p)\)

这启示我们关注一条到根的链,假设已经确定了链上每条边删除时间的相对顺序,从底至上记为 \(t_m\dots t_0\),为了方便可以认为根有一条父边且删除时间为 \(0\)

若在链尾新接一条边 \((u,fa)\),其删除时间为 \(t_{m+1}\),考虑 \(u\) 可以选择和哪些点建边,容易发现它们一定是 \(t_m\dots t_0\) 的单调栈里的点(栈单调递减)。

于是可以 dp,记 \(f_{u,i}\) 表示已知 \(t_m\dots t_0\) 的单调栈大小为 \(i+1\) 时(显然 \(t_0=0\) 一定在栈内),\(u\) 子树内的点的向上建边方案。转移枚举加入 \(t_{m+1}\) 后单调栈的大小即可,子树相互独立故直接相乘:

\[f_{u,i}=\sum\limits_{j=1}^{i+1}\prod f_{v,j} \]

考虑边界条件(即叶子),记叶子到根有 \(dep\) 条边,则:

\[f_{u,i}=i+1 \]

最后答案即为 \(\prod\limits_{v\in son_n} f_{v,0}\)

复杂度 \(O(n^3)\),前缀和优化一下就 \(O(n^2)\)

代码

#include<bits/stdc++.h>
using namespace std;

#define int long long
const int N = 3e3 + 5, mod = 998244353;
int n, u, v, f[N][N], ans = 1;
vector<int> to[N];

inline void dfs(int u, int fa, int dep){
	bool leaf = true; 
	for(auto v : to[u]) if(v ^ fa) leaf = false, dfs(v, u, dep + 1);
	for(int i = 0; i <= dep - 1; ++i){
		int res = 1;
		for(auto v : to[u]) if(v ^ fa) res = res * f[v][i + 1] % mod;
		f[u][i] = ((!i ? 0 : f[u][i - 1]) + res) % mod;
	}
	if(leaf) for(int i = 0; i <= dep - 1; ++i) f[u][i] = i + 1;
}
signed main(){
	cin >> n;
	for(int i = 1; i < n; ++i) scanf("%lld%lld", &u, &v), to[u].push_back(v), to[v].push_back(u);
	dfs(n, 0, 0);
	for(auto v : to[n]) ans = ans * f[v][0] % mod;
	cout << ans;
	return 0;
}
posted @ 2026-01-15 08:18  Zwi  阅读(2)  评论(0)    收藏  举报