HDU 5371 Hotaru's problem

题意:给你一串数字,要你找到这里面最大的N-序列的长度。N序列满足下面两个条件:1、第一部分与第三部分相同;  2、第一部分与第二部分对称;例如:2,3,4,4,3,2,2,3,4 就是一个N-序列。通过观察,我们知道N序列包含两个回文序列,上面的例子中2,3,4,4,3,2和4,3,2,2,3,4 两个回文。由于题目中给的数据量比较大,所以暴力肯定超时。所以用到了处理回文序列的Manacher算法。该算法的核心是利用回文串左右对称的性质,例如有个回文串 1 2 1 3 4 3 1  2 1,可以看到,4的左边和右边对称,最大对称长度为4,。以4左边的2为中心的最大对称长度为1(1,2,1为回文序列,2为中心,对称长度为1),所以,以4右边的2为中心的最大对称长度也为1,这只是一种情况。当回文串为 1 2 1 3 4 3 1 2 1 3时,以右边的2为中心的最大对称长度就为2了,但我们可以确定的是,以右边的2为中心的最大对称长度一定不小于1,否则以4为中心的最大对称长度就不会是4了。这里给个关于此算法详细解释的链接http://blog.csdn.net/ggggiqnypgjg/article/details/6645824

理解之后就可以做题了。注意的是,用此方法求的只是最大对称长度,而可能N-序列的两个回文长度不是对称中心的最大对称长度,例如在2 2 3 4 4 3 2 2 3 4中,2 2 3 4 4 3 2 2是回文串,但它不是N-序列中的回文串,那两个回文串依旧是2 3 4 4 3 2和4 3 2 2 3 4。

代码如下

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
using namespace std;
int n;
const int maxn=1e+5+5;
int a[2*maxn];
typedef struct
{
    int p;
    int num;
}h;
h pp[2*maxn];

bool cmp(const h &a,const h &b)
{
    if(a.p>b.p)
        return true;
    if(a.p==b.p&&a.num<b.num)
        return true;
    return false;
}
void KP()
{
     int mx=0;
     int id;
     for(int i=1;i<=2*n+1;i++)
     {
         pp[i].num=i;
         if(mx>i)
            pp[i].p=min(pp[2*id-i].p,mx-i);
         else
            pp[i].p=1;
        while(a[pp[i].p+i]==a[i-pp[i].p])pp[i].p++;
        if(pp[i].p+i>mx)
        {
            mx=pp[i].p+i;
            id=i;
        }
     }
}
set<int>T;
set<int>::iterator it;
int max_s()
{
     KP();//即Manacher算法
     sort(pp+1,pp+2*n+2,cmp);
     int M=0;
     T.clear();//一定要注意初始化啊
     for(int i=1;i<=2*n+1;i++)
     {
         int u=pp[i].num;
         if(a[u]!=-1)continue;
         if(pp[i].p==1) break;
         T.insert(u);
         it=T.lower_bound(u+pp[i].p);//也可以写成it=T.upper_bound(u+pp[i].p);
         it--;
         M=max(M,*it-u);
         it=T.lower_bound(u-pp[i].p);
         M=max(M,u-*it);
     }
     return (M/2)*3;
}
int main()
{
    int cc;
    scanf("%d",&cc);
    int cnt=0;
    while(cnt<cc)
    {
        cnt++;
        scanf("%d",&n);
        a[1]=-1;
        a[0]=-2;
        for(int i=2;i<=n*2;i+=2)
        {
            scanf("%d",&a[i]);
            a[i+1]=-1;
        }
        a[n*2+2]=-3;
       int ans=max_s();
        printf("Case #%d: %d\n",cnt,ans);
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章