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(" "); FOR(i,1,cnt) printf("%3d",p[i]); printf(" "); **/ } 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 ",ans); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。