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

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