[CF30E]Tricky and Clever Password(KMP+manacher)

首先枚举回文中心,然后显然中心两边要尽量扩展作为middle,这个用manacher实现。

然后注意到suffix的结尾位置是固定的(串尾),那么预处理出以每个位置结尾的串与原串后缀至多能匹配多长,然后再作个前缀和在枚举回文中心时尝试更新答案即可。这一部分将原串反过来用KMP实现,注意|suffix|可能为0。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 6 typedef long long ll;
 7 using namespace std;
 8 
 9 const int N=100010;
10 char s[N],ss[N];
11 int n,ans,pos,mx,id,nxt[N],r[N],f[N],g[N];
12 
13 int main(){
14     freopen("e.in","r",stdin);
15     freopen("e.out","w",stdout);
16     scanf("%s",s+1); n=strlen(s+1); s[n+1]='#';
17     rep(i,1,n){
18         r[i]=(mx>i) ? min(r[2*id-i],mx-i) : 1;
19         while (s[i+r[i]]==s[i-r[i]]) r[i]++;
20         if (r[i]+i>mx) mx=r[i]+i,id=i;
21     }
22     rep(i,1,n) ss[i]=s[n+1-i];
23     nxt[0]=nxt[1]=0;
24     for (int i=2,j=0; i<=n; i++){
25         while (j && ss[j+1]!=ss[i]) j=nxt[j];
26         if (ss[j+1]==ss[i]) nxt[i]=++j;
27     }
28     for (int i=1,j=0; i<=n; i++){
29         while (j && ss[j+1]!=s[i]) j=nxt[j];
30         if (ss[j+1]==s[i]) f[i]=++j;
31         if (f[i]==n) j=nxt[j];
32         if (f[i]) g[i]=i-f[i]+1;
33     }
34     rep(i,1,n) if (f[i-1]>f[i]) f[i]=f[i-1],g[i]=g[i-1];
35     bool flag=0;
36     rep(i,1,n) if (2*r[i]-1>ans) ans=2*r[i]-1,pos=i-r[i]+1;
37     rep(i,1,n){
38         int t=i-r[i];
39         if (2*min(f[t],n-(i+r[i]-1))+2*r[i]-1>ans) flag=1,ans=2*min(f[t],n-(i+r[i]-1))+2*r[i]-1,pos=i;
40     }
41     if (!flag) printf("1
%d %d
",pos,ans);
42         else printf("3
%d %d
%d %d
%d %d
",g[pos-r[pos]],f[pos-r[pos]],pos-r[pos]+1,2*r[pos]-1,n-f[pos-r[pos]]+1,f[pos-r[pos]]);
43     return 0;
44 }
原文地址:https://www.cnblogs.com/HocRiser/p/11107473.html