1033 小A的回文串 manacher
链接:https://ac.nowcoder.com/acm/problem/23501
来源:牛客网
题目描述
小A非常喜欢回文串,当然我们都知道回文串这种情况是非常特殊的。所以小A只想知道给定的一个字符串的最大回文子串是多少,但是小A对这个结果并不是非常满意。现在小A可以对这个字符串做一些改动,他可以把这个字符串最前面的某一段连续的字符(不改变顺序)移动到原先字符串的末尾。那么请问小A通过这样的操作之后(也可以选择不移动)能够得到最大回文子串的长度是多少。
输入描述:
一行一个字符串表示给定的字符串S一行一个字符串表示给定的字符串S一行一个字符串表示给定的字符串S
输出描述:
一行输出一个整数,表示通过这样的操作后可以得到最大回文子串的长度。
备注:
N表示字符串的长度,1≤N≤5000N表示字符串的长度,1 \leq N \leq 5000N表示字符串的长度,1≤N≤5000
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; } /*样例区 */ //------------------------------------------------------------