刚开始拿上这道题,没有一点思路,看了提示,说kmp处理前后缀,才恍然大悟,加上dp处理结果,妙哉。
#include<bits/stdc++.h>
using namespace std;
const int MAX_N = 2e6+10; // Trie 树上的最大结点数
const int MAX_C = 26; // 每个结点的子结点个数上限
int dp[MAX_N];
struct Trie {
int *ch[MAX_N]; // ch 保存了每个结点的 26 个可能的子结点编号,26 对应着 26 种小写字母,也就是说,插入的字符串全部由小写字母组成。初始全部为 -1
int tot; // 总结点个数(不含根结点),初始为 0
int cnt[MAX_N]; // 以当前结点为终端结点的 Trie 树中的字符串个数
void init() { // 初始化 Trie 树,根结点编号始终为 0
tot = 0;
memset(cnt, 0, sizeof(cnt));
memset(ch, 0, sizeof(ch)); // 将 ch 中的元素初始化为 NULL
}
void insert(char *str,int *Next,int idx) {
int p = 0; // 从根结点(0)出发
for (int i = 0; str[i]; ++i) {
if (ch[p] == NULL) {
ch[p] = new int[MAX_C]; // 只有 p 当包含子结点的时候才去开辟 ch[p] 的空间
memset(ch[p], -1, sizeof(int) * MAX_C); // 初始化为 -1
}
if (ch[p][str[i] - 'A'] == -1) { // 该子结点不存在
ch[p][str[i] - 'A'] = ++tot; // 新增结点
}
p = ch[p][str[i] - 'A']; // 在 Trie 树上继续插入字符串 str+
if(cnt[p]){
if(Next[strlen(str)-i-1]==i+1){
dp[idx]=max(dp[idx],dp[cnt[p]]+1);
}
}
}
cnt[p]=idx;
}
}trie;
int Next[MAX_N];
void getnext(char* t)
{
int i,len=strlen(t);
Next[0]=len;
for(i=0;i<len-1&&t[i]==t[i+1];i++);
Next[1]=i;
int a=1;
for(int k=2;k<len;k++){
int p=a+Next[a]-1,l=Next[k-a];
if(k+l-1>=p){ //l>=p-k+1
int j=max(p-k+1,0);
while(k+j<len&&t[k+j]==t[j]) j++;
Next[k]=j;a=k;
}else Next[k]=l;
}
}
char s[MAX_N];
int main() {
int n;
scanf("%d",&n);
trie.init();
for(int i=1;i<=n;i++){
scanf("%s",s);
getnext(s);
trie.insert(s,Next,i);
}
int ans=0;
for(int i=1;i<=n;i++){
ans=max(ans,dp[i]);
}
printf("%d\n",ans+1);
return 0;
}