找出以每一个点作为尾端的最长区间然后就变成了一道很简单的区间完全覆盖问题,倒过来直接上贪心就好了,至于如何找最长区间需要用到回文树
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 50021
using namespace std;
int n,p,ch[maxn][26],fail[maxn],len[maxn],N,s[maxn];
int last,cnt;
char ss[maxn];
struct edge{
int l,r;
edge(int a=0,int b=0):l(a),r(b){}
}e[maxn];
int newnode(){
memset(ch[p],0,sizeof(ch[p]));
fail[p]=len[p]=0;
return p++;
}
int get(int x){
while(s[n]!=s[n-len[x]-1])x=fail[x];
return x;
}
void insert(int c,int id){
s[++n]=c;
int cur=get(last);
if(!ch[cur][c]){
int now=newnode();
fail[now]=ch[get(fail[cur])][c];
len[now]=len[cur]+2;
ch[cur][c]=now;
}
last=ch[cur][c];
e[++cnt]=edge(n-len[last],id);
}
int main(){
while(scanf("%s",ss)!=EOF){
p=n=cnt=last=0,s[0]=-1;
len[newnode()]=0;
len[newnode()]=-1;
fail[0]=1;
N=strlen(ss);
for(int i=0;i<N;i++)insert(ss[i]-'a',i);
int ans=0,ml=N,now=N+1;
for(int i=cnt;i>=1;i--){
if(e[i].l<ml)ml=e[i].l;
if(e[i].r<now)now=ml,ans++;
}
printf("%d\n",ans-1);
}
return 0;
}