Description
定义一个子串,子串由三部分组成,其中第一部分和第三部分相同,第一部分和第二部分对称。给出一个n个数的序列,问序列中最长的符合要求的子串的长度
Input
第一行一整数T表示用例组数,每组用例首先输入一整数n表述序列长度,之后n个整数ai表示该序列(T<=20,n<=100000,0<=ai<=10^9)
Output
对于每组用例,输出序列中最长的符合要求的子串的长度
Sample Input
1
10
2 3 4 4 3 2 2 3 4 4
Sample Output
Case #1: 9
Solution
题目中定义的所谓子串其实就是两个等长回文串且第一个回文串后半部分和第二个回文串前半部分重叠,首先对原序列做一遍Manacher得到以每个字符为中心的回文串的最长长度,之后枚举第一个回文串的中心i,那么第二个回文串的中心j最远为i+ma[i]-1,只要ma[j]>=j-i+1,说明以i,j为中心的这两个回文串组合起来就是符合条件的子串,故在枚举的过程中更新最优解即可
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 111111
int ss[2*maxn],ma[2*maxn];
void Manacher(int *s,int len)
{
int l=0;
ss[l++]=-2;
ss[l++]=-1;
for(int i=0;i<len;i++)
{
ss[l++]=s[i];
ss[l++]=-1;
}
ss[l]=0;
int mx=0,id=0;
for(int i=0;i<l;i++)
{
ma[i]=mx>i?min(ma[2*id-i],mx-i):1;
while(ss[i+ma[i]]==ss[i-ma[i]])ma[i]++;
if(i+ma[i]>mx)
{
mx=i+ma[i];
id=i;
}
}
}
int T,n,a[maxn];
int main()
{
scanf("%d",&T);
for(int Case=1;Case<=T;Case++)
{
scanf("%d",&n);
for(int i=0;i<n;i++)scanf("%d",&a[i]);
Manacher(a,n);
int ans=0;
for(int i=1;i<2*n+2;i+=2)
for(int j=i+ma[i]-1;j-i>ans;j-=2)
if(j-i+1<=ma[j])
{
ans=max(ans,j-i+1);
break;
}
printf("Case #%d: %d\n",Case,ans/2*3);
}
return 0;
}