1. 程式人生 > >V - 吉哥系列故事――完美隊形II manacher變形

V - 吉哥系列故事――完美隊形II manacher變形

       吉哥又想出了一個新的完美隊形遊戲! 
  假設有n個人按順序站在他的面前,他們的身高分別是h[1], h[2] ... h[n],吉哥希望從中挑出一些人,讓這些人形成一個新的隊形,新的隊形若滿足以下三點要求,則就是新的完美隊形: 

  1、挑出的人保持原隊形的相對順序不變,且必須都是在原隊形中連續的; 
  2、左右對稱,假設有m個人形成新的隊形,則第1個人和第m個人身高相同,第2個人和第m-1個人身高相同,依此類推,當然如果m是奇數,中間那個人可以任意; 
  3、從左到中間那個人,身高需保證不下降,如果用H表示新隊形的高度,則H[1] <= H[2] <= H[3] .... <= H[mid]。 

  現在吉哥想知道:最多能選出多少人組成新的完美隊形呢?

 

 

這道題正確解決方案就是manacher 判斷下單調遞增即可

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<string.h>
using namespace std;
const int maxn=101000;
int  num[maxn];
int nn[maxn<<1];
int Lis[maxn<<1];
int Proprocess(const int* str,int len,int *p)//0 代表#
{
    int top=0;
    p[top++]=-1;
    for(int i=0;i<len;++i)
    {
        p[top++]=0;
        p[top++]=str[i];
    }
    p[top++]=0;
    p[top]=-2;
    return top;
}
int  Mannacher(const int* str,int len)//經過預處理的字串
{
    int r;//r為上一個中心對應的半徑
    int mid=0;//中心
    memset(Lis,0,sizeof(Lis));
    for(int i=1;i<len;++i)//計算以i為中心的字串的
    {
        if(i<=mid+r)
        {
            r=min(Lis[2*mid-i],mid-i+r);
        }
        else
            r=0;
        while(str[i+r+1]==str[i-r-1]&&str[i+r+1]<=str[i+r-1])//相等的情況下 保持遞增
             r++;
        Lis[i]=r;
        mid=i;
    }
    int ans=-1;
    for(int i=1;i<len;++i)
        ans=ans>Lis[i]?ans:Lis[i];
    return ans;

}
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
       scanf("%d",&n);
       for(int i=0;i<n;i++)
            scanf("%d",num+i);
       n=Proprocess(num,n,nn);
       int ans=Mannacher(nn,n);
       cout<<ans<<endl;
    }
}

 

但是這道題我一次做的時候做錯了  當時也想了一個o(n)的方法,  直接讓下一個判斷的中心為上一個迴文串的右

邊緣+1。因為疏忽上一個迴文串可能全相等的情況 所以錯了

放一個數據

1

12
50 50 50 50 50 50 50 50 50 50 50 50

 

錯誤程式碼(給自己提個醒)

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<string.h>
using namespace std;
const int maxn=101000;
int  num[maxn];
int nn[maxn<<1];
int Lis[maxn<<1];
int Proprocess(const int* str,int len,int *p)//0 代表#
{
    int top=0;
    p[top++]=-1;
    for(int i=0;i<len;++i)
    {
        p[top++]=0;
        p[top++]=str[i];
    }
    p[top++]=0;
    p[top]=-2;
//    for(int i=0;i<=top;++i)
//        cout<<p[i]<<" ";
//    cout<<endl;
    return top;
}
int  Mannacher(const int* str,int len)//經過預處理的字串
{
    int mid,r,maxx;
    mid=0,r=0;
    memset(Lis,0,sizeof(Lis));
    for(int i=1;i<len;)//計算以i為中心的字串的
    {
        maxx=str[i]?str[i]:300;//作為首先最大字元
        r=0;
        while(str[i+r+1]==str[i-r-1])
        {
             if(str[i+r+1])
             {
                 if(str[i+r+1]>maxx)//不符合
                    break;
                maxx=str[i+r+1];//符合 並且更換最大值
             }
             r++;
        }
        Lis[i]=r;
        mid=i;
        if(r)
           i=mid+r;
        else
            i=mid+r+1;//需要從0處開始
    }
    int ans=-1;
    for(int i=1;i<len;++i)
        ans=ans>Lis[i]?ans:Lis[i];
    return ans;

}
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
       scanf("%d",&n);
       for(int i=0;i<n;i++)
            scanf("%d",num+i);
       n=Proprocess(num,n,nn);
       int ans=Mannacher(nn,n);
       cout<<ans<<endl;
    }
}