1033 小A的回文串 manacher

 

链接:https://ac.nowcoder.com/acm/problem/23501
来源:牛客网

题目描述

小A非常喜欢回文串,当然我们都知道回文串这种情况是非常特殊的。所以小A只想知道给定的一个字符串的最大回文子串是多少,但是小A对这个结果并不是非常满意。现在小A可以对这个字符串做一些改动,他可以把这个字符串最前面的某一段连续的字符(不改变顺序)移动到原先字符串的末尾。那么请问小A通过这样的操作之后(也可以选择不移动)能够得到最大回文子串的长度是多少。

输入描述:

一行一个字符串表示给定的字符串S一行一个字符串表示给定的字符串SS

输出描述:

一行输出一个整数,表示通过这样的操作后可以得到最大回文子串的长度。
示例1

输入

复制
dcbaabc

输出

复制
7

说明

将前面的dcba移动到末尾变成abcdcba,这个字符串的最大回文子串就是它本身,长度为7

备注:

N表示字符串的长度,1≤N≤5000N表示字符串的长度,1 \leq  N \leq 5000N1N5000

manacher分析

 

 

 

 

 

 

 

 

 

  • 对于一个回文串,有且仅有一个对称中心。且叫它回文对称中心。
  • 在一个回文串内,任选一段区间 X ,一定存在关于"回文对称中心"对称的一个区间 Y ,且把这个区间 Y 叫做关于区间 X 的对称区间。
  • 区间和对称区间一定全等。(你都是对称的怎么可能不全等)
  • 若一个区间的对称区间是回文串,这个区间必定是一个回文串。在大的回文串内,它们回文半径相等。
  • 然而我们通过确定关系预先得到的回文半径,它的数值,必定小于等于这个位置真实的回文串半径。
//-------------------------代码----------------------------

//#define int LL
const int N = 1e5+10;
int n,m;
string s;
string str;
int p[10050];

void getstr(int l,int r)
{
    str.clear();
    str.push_back('$');
    for(int i = l;i<r;i++) {
        str.pb('#');
        str.pb(s[i]);
    }
    str.pb('#');
}

void manacher() {
    int mx = 0,id;
    // cout<<str.size()<<endl<<s.size()<<endl;
    for(int i = 1;i<str.size();i++) {
        if(mx>i) p[i]=min(p[2*id-i],mx-i);
        else p[i] = 1;
        while(str[i+p[i]]==str[i-p[i]]) {
            p[i] ++ ;
        }
        if(p[i] + i > mx) {
            mx = p[i] + i,id = i;
        }
    }
}

void solve()
{
    cin>>s;
    int n = s.size();
    s = s + s;
    int ans = 1;
    for(int i = 0;i<n;i++) {
        getstr(i,i+n);
        manacher();
        for(int j = 1;j<s.size();j++) {
            ans = max(ans,p[j]);
        }
    }
    cout<<ans - 1<<endl;
}

signed main(){
clapping();TLE;

// int t;cin>>t;while(t -- )
solve();
// {solve(); }
return 0;
}

/*样例区


*/

//------------------------------------------------------------

 

posted @ 2022-07-12 15:08  er007  阅读(62)  评论(0编辑  收藏  举报