Manacher基础学习

马拉车的模板

void init(){
    int k=0;
    ma[k++] ='$';
    for(int i=0;i<n;i++){//n是s的长度
        ma[k++]='#';
        ma[k++]=s[i];
    }
    ma[k++]='#';
    len=k;
}

int Manacher(){
  Len[0]=0;
  int sum = 0,id=0,mx = 0;
  for(int i=1;i<len;i++){
    if(i < mx) Len[i] = min(mx - i, Len[2 * id - i]);
    else Len[i] = 1;
    while(i-Len[i]>0 && i+Len[i]<len && ma[i - Len[i]]== ma[i + Len[i]]){
        Len[i]++;
    }
    if(Len[i] + i > mx){
      mx = Len[i] + i;
      id = i;
      sum=max(Len[i],sum);
    }
  }
  return (sum - 1);
}

ma[]  $ # a # b # a # a #

Len[]    1 2 1 4 1 2 3 2 1

复杂度o(n)

模板题1hdu3068,问最长的回文字符长度

模板题2 hdu3294,问这个字符在字符串中最长回文子串,然后就好了

因为两题真就模板题,就只放3068的了

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define il inline
#define it register int
#define inf 0x3f3f3f3f
#define lowbit(x) (x)&(-x)
#define pii pair<int,int>
#define mak(n,m) make_pair(n,m)
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 998244353
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
const int maxn=1e6+10;
int t;
char s[maxn];
char ma[maxn*2];
int Len[maxn*2],len,pos;
void init(int l){
    int k=0;
    ma[k++] = '$';
    for(int i=0;i<l;i++){
        ma[k++]='#';
        ma[k++]=s[i];
    }
    ma[k++]='#';
    len=k;
}

int Manacher(){
  Len[0]=0;
  int sum = 0,id=0,mx = 0;
  for(int i=1;i<len;i++){
    if(i < mx) Len[i] = min(mx - i, Len[2 * id - i]);
    else Len[i] = 1;
    while(i-Len[i]>0 && i+Len[i]<len && ma[i - Len[i]]== ma[i + Len[i]]) Len[i]++;
    if(Len[i] + i > mx){
      mx = Len[i] + i;
      id = i;
      sum=max(Len[i],sum);
    }
  }
  return (sum - 1);
}
int main() {
    while(~scanf("%s",s)){
        init(strlen(s));
        printf("%d\n",Manacher());
    }
    return 0;
}

 

 

模板题3 hdu4513 ,问一排身高的人,有多少是凸起回文身高

比如2 3 2算3 但2 1 2算1

其实就是里面将ma[i-Len[i]+2]>=ma[i-Len[i]]的条件。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define il inline
#define it register int
#define inf 0x3f3f3f3f
#define lowbit(x) (x)&(-x)
#define pii pair<int,int>
#define mak(n,m) make_pair(n,m)
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 998244353
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
const int maxn=1e5+10;
int t,n;
int s[maxn];
int ma[maxn*2];
int Len[maxn*2],len,pos;
void init(){
    int k=0;
    ma[k++] = -2;
    for(int i=0;i<n;i++){
        ma[k++]=-1;
        ma[k++]=s[i];
    }
    ma[k++]=-1;
    len=k;
}

int Manacher(){
  Len[0]=0;
  int sum = 0,id=0,mx = 0;
  for(int i=1;i<len;i++){
    if(i < mx) Len[i] = min(mx - i, Len[2 * id - i]);
    else Len[i] = 1;
    while(i-Len[i]>0 && i+Len[i]<len && ma[i - Len[i]]== ma[i + Len[i]] && ma[i-Len[i]+2]>=ma[i-Len[i]]){
        Len[i]++;
    }
    if(Len[i] + i > mx){
      mx = Len[i] + i;
      id = i;
      sum=max(Len[i],sum);
    }
  }
  return (sum - 1);
}
int main() {
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(it i=0;i<n;i++){
            scanf("%d",&s[i]);
        }
        init();
        printf("%d\n",Manacher());
    }
    return 0;
}

 

 

Codeforces Global Round 7 D题

题意:

给t个字符串s,题意好难说啊,

样例输入                            输出

5                     
a                                         a
abcdfdcecba                      abcdfdcba
abbaxyzyx                          xyzyx
codeforces                         c或者s
accbbca                             acbbca

就是求s的前缀,和s的后缀组成最长的回文子串,输出它

样例二s的前缀abcdfd和s的后缀cba可以组成abcdfdcba

思路:

如果头和尾是相等,往里找,头和尾不相等的,比如第五个样例accbbca,ac是相等的所以只要cbb里找两头最长的回文字符串,直接马拉车

找位置的时候需要条件要符合i-Len[i]==0 or i+Len[i]==len(模拟赛的时候这个条件没看到直接裂开了,而且本来的马拉车模板是错的)

 

 

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define il inline
#define it register int
#define inf 0x3f3f3f3f
#define lowbit(x) (x)&(-x)
#define pii pair<int,int>
#define mak(n,m) make_pair(n,m)
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 998244353
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
const int maxn=1e6+10;
int t;
char s[maxn],ss[maxn];
char ma[maxn*2];
int Len[maxn*2],cc,pos;
void init(int l,int r){
    int k=0;
    ma[k++] = '$';
    for(int i=l;i<=r;i++){
        ma[k++]='#';
        ma[k++]=s[i];
    }
    ma[k++]='#';
    cc=k;
}

int Manacher(){
  Len[0]=0;
  int sum = 0,id=0,mx = 0;
  pos=0;
  for(int i=1;i<cc;i++){
    if(i < mx) Len[i] = min(mx - i, Len[2 * id - i]);
    else Len[i] = 1;
    while(i-Len[i]>0 && i+Len[i]<cc && ma[i - Len[i]]== ma[i + Len[i]]) Len[i]++;
    if(Len[i] + i > mx){
      mx = Len[i] + i;
      id = i;
      if(Len[i]>sum &&( i-Len[i]==0 || i+Len[i]==cc)){
        sum=Len[i];pos=i;
     }
    }
  }
  return (sum - 1);
}
int main() {
    scanf("%d",&t);
    while(t--){
        scanf("%s",s);
        int ls=strlen(s);
        int l=0,r=ls-1;
        while(s[l]==s[r] && l<=r){
            ss[l]=s[l];l++;r--;
        }
        if(l>r){
            printf("%s\n",s);continue;
        }
        init(l,r);
        int chang=Manacher();
        for(it i=0;i<l;i++){
            printf("%c",ss[i]);
        }
        for(it i=pos-chang+1;i<=pos+chang-1;i+=2){
            printf("%c",ma[i]);
        }
        for(it i=l-1;i>=0;i--){
            printf("%c",ss[i]);
        }
        printf("\n");
    }
    return 0;
}

 

 

 

 

 

 

求回文子串的个数

 

int Manacher(){
  Len[0]=0;
  int sum = 0,id=0,mx = 0,cnt=0;
  pos=0;
  for(int i=1;i<cc;i++){
    if(i < mx) Len[i] = min(mx - i, Len[2 * id - i]);
    else Len[i] = 1;
    while(i-Len[i]>0 && i+Len[i]<cc && ma[i - Len[i]]== ma[i + Len[i]]) Len[i]++;
    if(Len[i] + i > mx){
      mx = Len[i] + i;
      id = i;
    }
    cnt+=Len[i]/2;
  }
  return cnt;//cnt回文子串的个数
}

 

 

 

比如abaadada

有a b a a d a d a aba aa ada ada adada  dad 一共14个,cnt的输出也是14

 

 hdu5340

题意:

问给出的字符串能不能分割成三个回文字符串,能输出yes,不能输出no

思路:

因为Len[i]给的是这个字符回文半径,所以只要找i-Len[i]==0 or i+Len[i]==len,等于0的的右边界 l ,和和等于len的左边界 r ,的中间值是否大于l-r+1<Len[mid]*2,同时满足l<r

 

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll long long
#define ull unsigned long long
#define il inline
#define it register int
#define inf 0x3f3f3f3f
#define lowbit(x) (x)&(-x)
#define pii pair<int,int>
#define mak(n,m) make_pair(n,m)
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 998244353
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
const int maxn=2e4+10;
int n;
char s[maxn],ma[maxn*2];
int Len[maxn*2],len;
int pre1[maxn*2],pre2[maxn*2];
void init(int l){
    int k=0;
    ma[k++] ='$';
    for(int i=0;i<l;i++){
        ma[k++]='#';
        ma[k++]=s[i];
    }
    ma[k++]='#';
    len=k;
}

void Manacher(){
  Len[0]=0;
  int sum = 0,id=0,mx = 0;
  for(int i=1;i<len;i++){
    if(i < mx) Len[i] = min(mx - i, Len[2 * id - i]);
    else Len[i] = 1;
    while(i-Len[i]>0 && i+Len[i]<len && ma[i - Len[i]]== ma[i + Len[i]]){
        Len[i]++;
    }
    if(Len[i] + i > mx){
      mx = Len[i] + i;
      id = i;
    }
  }
  return ;
}
bool check(){
    int cout1=0,cout2=0;
    for(int i=1; i<len; i++){
        if(Len[i]-i==0 && i!=1) pre1[++cout1]=i;
        if(i+Len[i]==len && i != len-1) pre2[++cout2]=i;
    }
    int l, r, mid;
    for(int i =1; i<=cout1; i++){
        for(int j =1; j<= cout2; j++){
            l = pre1[i] + Len[pre1[i]] ;
            r = pre2[j] - Len[pre2[j]] ;
            if(l > r) continue;
            mid=(l+r)>>1;//cout<<Len[mid]<<ma[mid]<<endl;
            if(Len[mid]*2>(r - l + 1)){
                return true;
            }
        }
    }
    return false;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%s",s);
        int l=strlen(s);
        init(l);
        Manacher();
        if(check()){printf("Yes\n");}
        else{printf("No\n");}
    }
    return 0;
}

 

 

坚持自己所热爱的就是最好的

 

posted @ 2020-03-20 20:21  ouluy  阅读(153)  评论(0编辑  收藏  举报