传送门
记一下贪心的方法:从左往右扫。每个回文左端点记录了回文右端点的位置。
l
a
s
t
last
last记录上次的最右端。
m
a
x
R
maxR
maxR记录从
i
i
i往右走到
l
a
s
t
last
last过程中的最右端。
初始化
l
a
s
t
=
m
a
x
R
=
T
[
0
]
last=maxR=T[0]
last=maxR=T[0],
m
a
x
R
maxR
maxR会在移动的过程中不断更新。
当
i
i
i越过
l
a
s
t
last
last时,表示已经跨过覆盖的最大范围了。ans+=1,记录跨过的这个回文串。
然而最后一个串的右端点一定在整个串的右端点。跨过了之后退出循环。ans记录不到。
所以整个串覆盖至少需要(ans+1)个回文串。需要连接ans次。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
char s[maxn];int R[maxn],N,T[maxn],now,to,ans=0,last,maxR;
inline void manacher(){
int p=0,mx=0;
for(int i=0;i<=N;++i){
R[i]=(mx>i)?(min(mx-i+1,R[p*2-i])):1;
while(i>=R[i]&&s[i+R[i]]==s[i-R[i]]) R[i]++;
if(i+R[i]-1>mx) mx=i+R[i]-1,p=i;
T[i-R[i]+1]=max(T[i-R[i]+1],i+R[i]-1);
}
}
int main(){
while(scanf("%s",s)!=EOF){
memset(T,0,sizeof(T)),N=strlen(s),now=0,ans=0;
for(int i=N-1;i>=0;i--) s[(i+1)<<1]='#',s[(i<<1)+1]=s[i];
s[0]='#',N<<=1,manacher();
last=maxR=T[0];
for(int i=0;i<=N;i+=2){
if(i>last) ans++,last=maxR;
maxR=max(maxR,T[i]);
}printf("%d\n",ans);
}
}