【kuangbin專題】Manacher

[kuangbin專題] Manacher

 

A - Palindrome

這道題是一道板子題,就是求最長迴文串長度,直接構造mp數組然後遍歷一遍數組就可以了,或者構造mp數組時直接記錄最大值然後返回也可以。

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cstring>
using namespace std;

const int maxn = 1000010;
int mp[maxn*2];
char ma[maxn*2];

void Manacher(char s[], int len)
{
    int l = 0;
    ma[l++] = '$';
    ma[l++] = '#';
    for(int i=0;i<len;i++){
        ma[l++] = s[i];
        ma[l++] = '#';
    }
    ma[l] = 0;
    int mx = 0;
    int id = 0;
    for(int i=0;i<l;i++){
        mp[i] = mx>i?min(mp[id*2-i],mx-i):1;
        while(ma[i+mp[i]] == ma[i-mp[i]]) mp[i]++;
        if(mx<i+mp[i]){
            mx = i+mp[i];
            id = i;
        }
    }
}
char s[maxn];
int main()
{
    int cnt = 0;
    while(1){
        scanf("%s",&s);
        if(strcmp(s,"END")==0)
            break;
        cnt++;
        int len = strlen(s);
        Manacher(s,len);
        int ans = 0;
        for(int i=0;i<2*len+2;i++){
            ans = max(ans,mp[i]-1);
        }
        printf("Case %d: %d\n",cnt,ans);
    }
    return 0;
}

B - 吉哥系列故事——完美隊形II

這道題有一個小小的變化就是,要求從中間到兩邊,身高不下降,即h[1]<=h[2]<=h[3]...<=h[mid]。這道題本質還是一個板子題,只是在whlie循環向兩邊找時加上這個不下降的條件即可,另外這個迴文串不是字符串而是一個int型數組,所以不能插入#等字符,按照算法原來的意思是插入一個不可能出現的字符所以插入0或者-1或者小於0的任何一個數都可以。

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cstring>

#define mem(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 100005;
int mp[maxn<<1];
int ma[maxn<<1];
int manacher(int s[],int len)
{
    int mm = -1;
    int l=0;
    ma[l++] = -1;
    ma[l++] = 0;
    for(int i=0;i<len;i++){
        ma[l++] = s[i];
        ma[l++] = 0;
    }
    ma[l] = -2;
    int mx= 0;
    int id = 0;
    for(int i=0;i<l;i++){
        mp[i] = mx>i?min(mp[2*id-i],mx-i):1;
        while(ma[i+mp[i]]==ma[i-mp[i]]&&ma[mp[i]+i] <= ma[mp[i]+i-2]) mp[i]++;
        if(i+mp[i]>mx){
            mx = i+mp[i];
            id = i;
        }
        //printf("%d\n",mp[i]);
        mm = max(mm, mp[i]-1);
    }
    return mm;
}
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int s[maxn];
        int n;
        mem(mp, 0);
        scanf("%d", &n);
        for(int i = 0; i < n; i++)
        {
            scanf("%d", &s[i]);
        }
        int ans = manacher(s,n);
        printf("%d\n", ans);
    }
    return 0;
}

 C - Girls' research

這道題的題意是,輸入第一個字符代表a,然後後面是以第一個字符爲基準的,同樣是求迴文串,但是要換爲真實的串就是把第一個字符作爲a的那個對應的真實的串。

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
char  c,str[200009];
char  s[400009];
int   p[400009];
int   init( ){
	  int cur= 1;
	  s[0]='$';
	  s[1]='#';
	  int len = strlen( str );
	  for( int i=0;i<len;i++){
	  	   s[++cur]=str[i];
	  	   s[++cur]='#';
	  }
	  return cur;
}
void manacher( ){
	 int len = init();
	 int id ,mx =0;
	 int max_len = -1,index ;
	 for( int i=1;i<=len;i++){
	 	  if( i < mx ){
	 	  	  p[i] = min( mx - i , p[id*2-i] );
		   }
		  else p[i]=1;
		  while( s[i - p[i]] == s[i + p[i]] )
			         p[i]++;
		  if( i + p[i] > mx ){
			  	  mx = i + p[i];
				  id = i; 
		  }		  	  
		  if( p[i] - 1 > max_len ){
		  	  index = i ;
		  	  max_len = p[i] - 1;
		  } 
	 }
 	 if( max_len <2 ){
	 	 printf("No solution!\n");
	 }
	 else {
	 	 printf("%d %d\n",(index - max_len +1 )/2-1,(index + max_len -1 )/2-1 );
	 	 for( int i=  index - max_len +1  ;i<= index + max_len -1;i++ ){
	 	 	  if( s[i]!='$'&&s[i] != '#')
	 	 	      printf("%c",s[i]); 
		  }
		 printf("\n");
	 }
}
int main(void){ 
	while( scanf("%c",&c) !=EOF  ){
         
	       scanf("%s",str);
	       getchar();
		   int t =  c - 'a';
	       int len = strlen( str );  
	       for( int i=0;i<len;i++){
	       	 str[i] - c >= 0  ? str[i] = 'a' + str[i]-c : str[i] = 'a' + str[i] -c + 26; 
		   } 
		   manacher( );
	} 
	
	
	return 0;
} 

D - Making Huge Palindromes

這道題題意是,要把所給的字符串補成一個最短的迴文串然後輸出這個迴文串的長度。這道題可以轉化成,求出最長且包含最後一個字符的迴文串長度,然後用所給串的長度減去這個迴文串的長度就是要添加的長度,加上原串長度就是最終結果。

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1e6+5;
int mp[maxn<<1];
char ma[maxn<<1];
int l = 0;
void manacher(char s[], int len)
{
    ma[l++] = '$';
    ma[l++] = '#';
    for(int i=0;i<len;i++){
        ma[l++] = s[i];
        ma[l++] = '#';
    }
    int mx = 0;
    int id = 0;
    ma[l] = 0;
    for(int i=0;i<l;i++){
        mp[i] = mx>i?min(mp[id*2-i],mx-i):1;
        while(ma[i+mp[i]] == ma[i-mp[i]]) mp[i]++;
        if(mx<i+mp[i]){
            mx = i+mp[i];
            id = i;
        }
    }
    return ;
}

int main()
{
    int t=0;
    scanf("%d",&t);
    for(int k=1;k<=t;k++){
        memset(mp,0,sizeof(mp));
        l = 0;
        int ans = -1;
        char s[maxn];
        scanf("%s",&s);
        getchar();
        manacher(s,strlen(s));
        for(int i=0;i<l;i++){
            if(i+mp[i] == l){
                ans = max(ans,mp[i]-1);
            }
        }
        printf("Case %d: %d\n",k,2*strlen(s)-ans);
    }
    return 0;
}

這就是manacher算法的幾個基礎題了,進階題後續會給出。

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