1:先用Manacher预处理出以a[i]为中心的所有最长回文串的长度。
2:题目要求的子序列相当于两个回文串的叠加,暴力枚举第二个回文串的中心。(稍微加点优化,不然就t了)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#define ll long long
#define FOR(i,x,y) for(int i = x;i < y;i ++)
#define IFOR(i,x,y) for(int i = x;i > y;i --)
#define N 100010
using namespace std;
int str[N<<1],n,p[N<<1],cnt;
void Manacher(){
int mx,id;
p[1] = 1;
p[2] = 2;
mx = 3;
id = 2;
FOR(i,3,cnt+1){
int j = 2*id - i;
if(p[j] + i -1 < mx){
p[i] = p[j];
continue;
}
if(p[j] + i -1 >= mx){
id = i;
int l = 2*i - mx;
while(str[mx+1] == str[l-1]){
mx ++;
l --;
}
p[i] = mx - i +1;
}
}
/**
FOR(i,1,cnt) printf("%3d",str[i]);
printf("\n");
FOR(i,1,cnt) printf("%3d",p[i]);
printf("\n");
**/
}
int main()
{
//freopen("test.in","r",stdin);
int T,tCase = 0;
scanf("%d",&T);
while(T--){
printf("Case #%d: ",++tCase);
scanf("%d",&n);
cnt = 0;
int tem;
str[0] = -1;
FOR(i,0,n){
str[++cnt] = 0;
scanf("%d",&tem);
str[++cnt] = tem;
}
str[++cnt] = 0;
Manacher();
int ans = 0;
for(int i = 1;i <= cnt;i += 2){ ///只有str[i] == 0的点才可行
if(str[i] == 0){
if(p[i] <= ans) continue;
for(int j = p[i] + i - 1;(j-i) > ans;j -= 2){ ///暴力枚举所有右端点肯定跪。。。
if(p[j] > (j-i)){
ans = max(ans,j-i);
break;
}
}
}
}
ans = ans/2*3;
printf("%d\n",ans);
}
return 0;
}