题意:
密码是一个长度为奇数的回文串,现在我们对这个密码进行加密:把密码分成 3 段,最前面的 X 个字符为一段,最后面的 X 个字符为一段,剩余的字符为一段。这三段依次称之为 prefix, suffix, middle 。middle 的长度为一个大于 0 的奇数, prefix 、 suffix 的长度相等。加密后的密码即为 A + prefix + B + middle + C + suffix ,其中 A 、 B 、 C 是三个字符串,且都有可能为空, + 表示字符串相连。
先给出加密后的长度为n的字符串,求最长可能的密码串。
(n<=1e5)
Solution:
第一想法就是枚举middle然后计算最长的prefix和suffix
观察发现只需枚举以每个位置为中心的最长的回文串即可
发现suffix就是加密串的后缀,将suffix翻转后合prefix相同,那么我们就可以翻转加密串后和原串进行匹配,类似149E,定义pos[i]表示模式串中最早能匹配到第i个字符的位置,接着对于每个middle,二分prefix长度然后判断对应的suffix是否合法即可
复杂度 O(nlogn) O ( n log n )
找回文串可以用manacher,代码里使用的是二分+hash
处理pos数组可以用KMP,代码里使用的是z-box算法
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#define ull unsigned long long
using namespace std;
const int N=100010;
const int bas=211;
ull ha[N],fha[N],mi[N];
int n,z[2*N],cnt,pos[2*N];
struct huiwen{
int l,r;
}q[N];
char s[2*N];
int ans,pans[4],lans[4];
ull gha(int l,int r)
{
return ha[r]-ha[l-1]*mi[r-l+1];
}
ull fgha(int l,int r)
{
return fha[l]-fha[r+1]*mi[r-l+1];
}
void getpos(int i)
{
int r=min(i,n-i-1),l=0,ans=0;
while (l<=r)
{
int mid=l+r>>1;
if (gha(i-mid,i)==fgha(i,i+mid)) ans=mid,l=mid+1;
else r=mid-1;
}
q[i].l=i-ans,q[i].r=i+ans;
}
void findhw()
{
for (int i=0;i<n;i++)
getpos(i);
}
void zalo()
{
int l=0,r=0;
for (int i=1;i<=2*n;i++)
{
if (i<=n)pos[i]=1e9;
if (i>r)
{
int t=i,bg=0;
while (s[t]==s[bg]) t++,bg++;
z[i]=bg;
l=i,r=t-1;
}
else
{
if (i+z[i-l]-1<r) z[i]=z[i-l];
else
{
int t=r+1,bg=r-i+1;
while (s[t]==s[bg]) t++,bg++;
z[i]=bg;
l=i,r=t-1;
}
}
if (i>n) pos[z[i]]=min(pos[z[i]],i+z[i]-1-n);
}
for (int i=n-1;i>=1;i--) pos[i]=min(pos[i],pos[i+1]-1);
}
int main()
{
scanf("%s",s);
n=strlen(s);
ha[0]=s[0];
mi[0]=1;
for (int i=1;i<=n;i++) mi[i]=mi[i-1]*bas;
for (int i=1;i<n;i++) ha[i]=ha[i-1]*bas+s[i];
for (int i=n-1;i;i--) fha[i]=fha[i+1]*bas+s[i];
findhw();
s[n]='$';
for (int i=0;i<n;i++)
s[i+n+1]=s[i];
for (int i=0,j=n-1;i<j;i++,j--) swap(s[i],s[j]);
zalo();
for (int i=0;i<n;i++)
{
int l=q[i].r+1,r=n-1,as=-1;
while (l<=r)
{
int mid=l+r>>1;
if (pos[n-mid]<=q[i].l) as=mid,r=mid-1;
else l=mid+1;
}
if (as==-1) {
if (q[i].r-q[i].l+1>ans) ans=q[i].r-q[i].l+1,cnt=1,pans[1]=q[i].l,lans[1]=ans;}
else
{
if (q[i].r-q[i].l+1+2*(n-as)>ans)
{
ans=q[i].r-q[i].l+1+2*(n-as);
pans[1]=pos[n-as]-n+as,lans[1]=n-as;
pans[2]=q[i].l,lans[2]=q[i].r-q[i].l+1;
pans[3]=as,lans[3]=n-as;
cnt=3;
}
}
}
printf("%d\n",cnt);
for (int i=1;i<=cnt;i++) printf("%d %d\n",pans[i]+1,lans[i]);
}