HDU 5371 Manacher+暴力

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;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

原文地址:https://www.cnblogs.com/hqwhqwhq/p/4811891.html