V - 吉哥系列故事――完美隊形II manacher變形
阿新 • • 發佈:2018-11-04
吉哥又想出了一個新的完美隊形遊戲!
假設有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; } }