D. Hossam and (sub-)palindromic tree—树形dp

cf1771 Hossam and (sub-)palindromic tree

https://codeforces.ml/contest/1771/problem/D

题意

给出一颗n个节点的树,树上的每个节点都代表一个小写英文字母,求所有的\(s(u, v)\)(u到v的一条简单路径)中是回文串的最长子序列的长度。

思路

如果我们不考虑在树上,普通求最长回文子序列的长度是:
对于区间[u, v]
如果u == v dp[u][v] = 1

如果v == u + 1
(1)s[u] == s[v] dp[u][v] = 2
(2)s[u] != s[v] dp[u][v] = 1

其他
dp[u][v] = max(dp[u + 1][v], dp[u][v + 1])
s[u] == s[v] dp[u][v] = max(dp[u][v], d[u + 1][v - 1] + 2)

那对于树上的,如果我们能得出u, v的下内的节点是什么,那我们也可以类似做了。
因为节点数不多,我们可以以每个节点为根进行dfs,求出每个各节点相应情况下的nxt值
然后递归dp即可

#include <bits/stdc++.h>
#include <stdlib.h>
using namespace std;
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ll long long
#define int ll
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 2e3 + 5;
const int M = 1e6 + 5;
const ll mod = 1e9 + 7;

int n;
string s;
vector<int>g[N];
int nxt[N][N];
int dp[N][N];

void dfs(int root, int x, int fa){
	for(auto to : g[x]){
		if(to == fa) continue;
		nxt[root][to] = x;
		dfs(root, to, x);
	}
}

inline void cal(int u, int v){
	if(dp[u][v] != -1) return;
	if(u == v){
		dp[u][v] = 1;
		return;
	}

	if(nxt[u][v] == u){
		if(s[u] == s[v]) dp[u][v] = 2;
		else dp[u][v] = 1;
		return;
	}

	if(dp[u][nxt[u][v]] == -1) cal(u, nxt[u][v]);
	if(dp[nxt[v][u]][v] == -1) cal(nxt[v][u], v);
	dp[u][v] = max(dp[u][nxt[u][v]], dp[nxt[v][u]][v]);

	if(s[u] == s[v]){
		cal(nxt[v][u], nxt[u][v]);
		dp[u][v] = max(dp[u][v], dp[nxt[v][u]][nxt[u][v]] + 2);
	}
}

void init(){
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			dp[i][j] = -1;
			nxt[i][j] = 0;
		}
	}
	
	for(int i = 1; i <= n; i++) g[i].clear();
}

void solve()
{
	cin >> n;
	cin >> s;
	s = " " + s;
	init();

	for(int i = 1, u, v; i < n; i++){
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}

	for(int i = 1; i <= n; i++) 
		dfs(i, i, -1);

	int ans = 1;
	for(int i = 1; i <= n; i++){
		for(int j = i; j <= n; j++){
			cal(i, j);
			cal(j, i);
			ans = max({ans, dp[i][j], dp[j][i]});
			//cerr << ans << "\n";
		}
	}

	cout << ans << "\n";
}

signed main()
{
	IOS;
	int t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
}
posted @ 2022-12-25 10:25  Yaqu  阅读(52)  评论(0)    收藏  举报