[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\n%d %d\n",pos,ans); 42 else printf("3\n%d %d\n%d %d\n%d %d\n",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 }