题解 P6383 【『MdOI R2』Resurrection】
这道题与传统的树形dp不同
传统的树形dp是从子树中合并答案上来
即先确定子树对祖先的影响,然后确定当前节点的影响
这道题目显然不太好这样做,因为当前考虑的点的深度变小的时候,本来有限制的现在没有了限制,这样就非常不好设状态
那么我们反过来考虑,首先确定父亲对儿子的影响 然后dp。
首先观察可以发现 最终的答案肯定是这样的形态:
而没有:
就是父亲选好以后子树的点要么选父亲选的点上面的点 要么选父亲下面的点 而没有交叉的情况(手玩得证)
这样可以设
形式化的说就是
直接做是
code:
#include<bits/stdc++.h>
using namespace std;
const int N = 3e3 + 11;
const int mod = 998244353;
int f[N][N], n;
vector<int> G[N];
int dfs(int u, int res, int fa){
if(f[u][res] != -1)return f[u][res];
if(G[u].size() == 1){
return f[u][res] = res;
}
int &F = f[u][res];
F = 0;
if(res > 1)(F += dfs(u, res - 1, fa)) %= mod;
int sum = 1;
int s = G[u].size();
for(int i = 0;i < s; i++){
int v = G[u][i];
if(v == fa)continue;
sum = 1LL * sum * dfs(v, res + 1, u) % mod;
}
F = (F + sum) % mod;
return F;
}
int main(){
cin>>n;
int u, v;
memset(f, -1, sizeof f);
for(int i = 1;i < n; i++){
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
int ans = 1;
int s = G[n].size();
for(int i = 0;i < s; i++){
int v = G[n][i];
ans = 1ll * ans * dfs(v, 1, n) % mod;
}
printf("%d\n", ans);
return 0;
}