HDU 5371 Hotaru's problem(Manacher 求一序列三部分回文)

Hotaru's problem

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1268    Accepted Submission(s): 448


Problem Description
Hotaru Ichijou recently is addicated to math problems. Now she is playing with N-sequence.
Let's define N-sequence, which is composed with three parts and satisfied with the following condition:
1. the first part is the same as the thrid part,
2. the first part and the second part are symmetrical.
for example, the sequence 2,3,4,4,3,2,2,3,4 is a N-sequence, which the first part 2,3,4 is the same as the thrid part 2,3,4, the first part 2,3,4 and the second part 4,3,2 are symmetrical.

Give you n positive intergers, your task is to find the largest continuous sub-sequence, which is N-sequence.
 

Input
There are multiple test cases. The first line of input contains an integer T(T<=20), indicating the number of test cases. 

For each test case:

the first line of input contains a positive integer N(1<=N<=100000), the length of a given sequence

the second line includes N non-negative integers ,each interger is no larger than  109  , descripting a sequence.
 

Output
Each case contains only one line. Each line should start with “Case #i: ”,with i implying the case number, followed by a integer, the largest length of N-sequence.

We guarantee that the sum of all answers is less than 800000.
 

Sample Input
  
  
1 10 2 3 4 4 3 2 2 3 4 4
 

Sample Output
  
  
Case #1: 9
给你n个数 求一个最长的连续序列 可以分为3部分 ,其中第一部分和第二部分为回文,第二部分和第三部分回文
2 3 4 4 3 2 2 3 4 就是满足的一个序列
用Manacher算法求出Len[i] , Len[i] 表示回文的最右端到 i 的距离
#include <cstdio>
#include <algorithm>
#include <stdlib.h>
#include <cstring>
#include <iostream>
#include <cmath>
#define maxn 100010
using namespace std;
int a[maxn];
int tmp[maxn*2];
int Len[maxn*2];
int n;
int init(int s[])
{
    tmp[0]=-1;
    for(int i=1; i<=2*n; i+=2)
    {
        tmp[i] = 0;
        tmp[i+1] = s[i/2];
    }
    tmp[2*n+1] =0;
    tmp[2*n+2] = -2;
    return 2*n+1;
}
void Manacher(int s[],int len)
{
    int mx=0;
    int po=0;
    for( int i=1; i<=len; i++)
    {
        if(mx > i)
            Len[i] = min(mx-i , Len[2*po-i]);
        else
            Len[i] = 1;
        while( s[i-Len[i]]== s[i+Len[i]] )
        {
            Len[i]++;
        }
        if(Len[i]+i>mx)
        {
            po=i;
            mx=Len[i]+i;
        }
    }
}
int main()
{
    int T;
    int ca=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=0; i<n; i++)
            scanf("%d",&a[i]);
        int len = init(a);
        Manacher(tmp,len);
        int ans=1;
        for(int i=1; i<len; i+=2)
            for(int j=ans; j<=Len[i]; j+=2)        //对于满足要求的一个序列
            {                                       //分成三段的两个点为i ,i+j-1 (每一部分长度为j)
                if(Len[i]>=j && Len[i+j-1]>=j)     //对于i点 ,它右侧的回文长度大于j(即第二段长度)
                    {                              // 所以i+j-1点右侧回文长度也要大于j  
                        ans=j;
                    }
            }
        ans--;                              //   Manacher算法求出的ans-1位回文长度
        printf("Case #%d: ",ca++);          //   此时ans为第一部分 和 第二部分的长度和
        printf("%d\n",ans/2*3);
    }
    return 0;
}



 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值