题意
给你一个长度为n的字符串,让你求最长的回文子串长度。
数据范围
对于30%的数据,字符串长度≤1000
对于60%的数据,字符串长度≤〖10〗^6
对于100%的数据,字符串长度≤5*〖10〗^6,字符串仅包含小写字母
分析
明显的manacher,直接用manacher求一遍即可。
补充manacher
其实就是一个更新,看看现在的与以前的有没有关系,若有便可以继续更新,所以这是线性的。
由于这个算法是线性从前往后扫的。那么当我们准备求P[i]的时候,i以前的P[j]我们是已经得到了的。我们用mx记在i之前的回文串中,延伸至最右端的位置。同时用id这个变量记下取得这个最优mx时的id值。(注:为了防止字符比较的时候越界,我在这个加了‘#’的字符串之前还加了另一个特殊字符‘$’,故我的新串下标是从1开始的)
模板
mid:=0;
les:=0;
le:=le*2+1;
for i:=1 to le do begin
if les<=i then p[i]:=1 else p[i]:=min(p[mid*2-i],les-i);
while (i+p[i]<=le)and(i-p[i]>=1)and(st[i-p[i]]=st[i+p[i]]) do//拓展
inc(p[i]);
if p[i]+i>les then begin
les:=p[i]+i;
mid:=i;
end;
end;
代码:
var i,len,ans,mid,les:longint;p:array[0..15000000] of longint;str:ansistring;
st:array[0..15000000] of char;
function max(l,r:longint):longint;
begin
if l<r then exit(r) else exit(l);
end;
function min(l,r:longint):longint;
begin
if l>r then exit(r) else exit(l);
end;
begin
readln(str);
len:=length(str);
st[1]:='#';
for i:=1 to len do begin
st[i*2]:=str[i];
st[i*2+1]:='#';
end;
les:=0;mid:=0;len:=len*2+1;
for i:=1 to len do begin
if les<=i then p[i]:=1 else p[i]:=min(p[mid*2-i],les-i);
while (i+p[i]<=len)and(i-p[i]>=1)and(st[i+p[i]]=st[i-p[i]]) do inc(p[i]);
if p[i]+i>les then begin
les:=p[i]+i;
mid:=i;
end;
end;
for i:=1 to len do ans:=max(ans,p[i]-1);
writeln(ans);
end.