题目大意:给定一个字符串
S
,要求分成
|prefix|=|suffix|
|middle|
为奇数
prefix+middle+suffix
为回文串
除
middle
外所有段长度都可以为
0
要求最大化
首先我们发现
suffix
串是顶着右端点的,因此我们可以枚举
|suffix|
对于每个
|suffix|
我们需要求出最左侧能与
suffix
匹配的
prefix
我们发现随着
|suffix|
的增大,
prefix
的位置是单调不减的,因此我们可以用KMP算法求出对于每个
|suffix|
最靠左的
prefix
串
现在对于一个确定的
prefix
串和
suffix
串,我们需要求出中间的区间内最长的回文子串
middle
现在就是区间最长回文子串的问题了
一种做法是这样的:
首先利用Manacher算法求出以每个点为中心的最长回文半径,然后对于每次询问我们二分答案:
设询问区间为
[L,R]
,二分长度为
M
,那么如果
利用ST表即可做到单次询问
我还YY出了一种SB做法:
观察这个题的所有询问,我们发现询问区间是依次包含的
因此我们可以从最小的区间开始依次拓展
每次拓展,假设当前拓展的是
R
,那么我们需要用以
这个用回文自动机+树上倍增就可以了
= =所以说是傻逼做法嘛
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
#define MOD 999911657
#define BASE 2333
using namespace std;
int n,ans;
char s[M],rev_s[M];
int next[M],f[M],pos[M];
pair<int,int> intervals[M];
int log_2[M],a[M][17],_ans[M];
void KMP()
{
int i,fix=0;
for(i=2;i<=n;i++)
{
while( fix && rev_s[fix+1]!=rev_s[i] )
fix=next[fix];
if( rev_s[fix+1]==rev_s[i] )
++fix;
next[i]=fix;
}
fix=0;
for(i=1;i<=n;i++)
{
while( fix && rev_s[fix+1]!=s[i] )
fix=next[fix];
if( rev_s[fix+1]==s[i] )
++fix;
if( i+fix>=n )
return ;
if(!pos[fix])
{
pos[fix]=i;
intervals[fix]=make_pair(i+1,n-fix);
}
}
}
void Manacher()
{
int i,id=1,mx=1;
s[0]='$';
for(i=1;i<=n;i++)
{
f[i]=min(mx-i+1,f[id+id-i]);
while(s[i+f[i]]==s[i-f[i]])
++f[i];
if(i+f[i]-1>mx)
mx=i+f[i]-1,id=i;
}
}
int Get_Max(int x,int y)
{
int len=log_2[y-x+1];
return max(a[x][len],a[y-(1<<len)+1][len]);
}
int Bisection(int x,int y)
{
int l=1,r=y-x+2>>1;
while(l+1<r)
{
int mid=l+r>>1;
if( Get_Max(x+mid-1,y-mid+1)>=mid )
l=mid;
else
r=mid;
}
return Get_Max(x+r-1,y-r+1)>=r?r:l;
}
int main()
{
int i,j;
scanf("%s",s+1);n=strlen(s+1);
for(i=1;i<=n;i++)
rev_s[i]=s[n-i+1];
KMP();
Manacher();
pos[0]=1;intervals[0]=make_pair(1,n);
for(i=2;i<=n;i++)
log_2[i]=log_2[i>>1]+1;
for(i=1;i<=n;i++)
a[i][0]=f[i];
for(j=1;j<=log_2[n];j++)
for(i=1;i+(1<<j)-1<=n;i++)
a[i][j]=max(a[i][j-1],a[i+(1<<j-1)][j-1]);
for(i=0;pos[i];i++)
{
_ans[i]=2*Bisection(intervals[i].first,intervals[i].second)-1;
if(i*2+_ans[i]>ans*2+_ans[ans])
ans=i;
}
if(ans==0)
{
cout<<1<<endl;
for(i=1;i<=n;i++)
if(f[i]*2-1==_ans[0])
{
cout<<i-f[i]+1<<' '<<_ans[0]<<endl;
return 0;
}
}
else
{
cout<<3<<endl;
cout<<pos[ans]-ans+1<<' '<<ans<<endl;
int l=intervals[ans].first,r=intervals[ans].second;
for(i=l;i<=r;i++)
if( min(min(i-l,r-i)+1,f[i])*2-1==_ans[ans] )
{
cout<<i-(_ans[ans]>>1)<<' '<<_ans[ans]<<endl;
break;
}
cout<<n-ans+1<<' '<<ans<<endl;
}
return 0;
}