题目链接:
https://www.luogu.com.cn/problem/P7537
题意:
记字符串 和 的最长公共后缀为 。
当 时,认为这两个字符串是押韵的。
给定 个字符串(两两不相同),要求从其中组合出一个长度最长的字符串序列,使得序列中相邻的两个字符串押韵。
思路:
容易想到,将字符串翻转一下,后缀就变成了前缀,然后将字符串挂到字典树上。
如果要满足两个字符串的最大公共前缀长度 >= 最长的字符串的长度 - 1,只有两种情况。
设字符串为 ,字符为 。
那么只可能是 和 或者 和 。
设 为以字符 为结尾的字符串中,押韵字符串的最大数量。
对于一个字符串,要找最大押韵序列,它可以从自己的子节点转移过来,但是不能所有的节点都转移过来,只能有两个,如下图这种方式。
最中间的字符串找到的最大的押韵序列,就是它子节点中最大的两个孩子的数量之和。
同时,它也可以用剩余孩子,但是不能用它们的孩子。
比如:
a
ab
abc
abcd
ac
acd
acde
ad
ade
以上为翻转了之后的字符串,答案为 8。
所以对于 ,它的最大值就是最大的两个孩子的数量 + 自己 + 剩余有的孩子的数量。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 3e6 + 10;
char s[N];
LL ans;
struct Trie{
LL trie[N][26], cnt[N], dp[N], idx = 0;
void insert(char s[]){
LL u = 0, len = strlen(s);
for (int i = len - 1; i >= 0; i -- ){
LL v = s[i] - 'a';
if (!trie[u][v]) trie[u][v] = ++ idx;
u = trie[u][v];
}
cnt[u] ++ ;
}
void dfs(LL u){
LL mx1 = 0, mx2 = 0, count = 0;
for (int i = 0; i < 26; i ++ ){
LL v = trie[u][i];
if (!v) continue;
dfs(v);
count += cnt[v];
if (dp[v] > mx1){
mx2 = mx1;
mx1 = dp[v];
}
else if (dp[v] > mx2){
mx2 = dp[v];
}
}
if (cnt[u])
dp[u] = mx1 + max(count, 1LL);
ans = max(ans, mx1 + mx2 + max(0LL, count - 2) + cnt[u]);
}
}trie;
int main(){
ios::sync_with_stdio(false);cin.tie(0);
LL n;
cin >> n;
for (int i = 0; i < n; i ++ ){
cin >> s;
trie.insert(s);
}
trie.dfs(0);
cout << ans << "\n";
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现