HDU 3068 最长回文(马拉车模板题)

马拉车可以求出每个字符为中心的最长回文串 

# 1 # 2 # 2 # 1 # 2 # 2 #
1 2 1 2 5 2 1 6 1 2 3 2 1

'#'字符对应的p[i]对应的回文串在原串s里都是偶数长度的,而'1','2'对应的p[i]对应的回文串在原串s里都是奇数长度的

总结O(n)求最长回文子串,关键是p[i]数组,p[i]表示的是处理过的字符串t里以i位置字符为中心的最长回文子串半径然后,p[i]-1得到的就是以i位置字符为中心的最长回文子串长度(在s串里),然后如果要确定一个回文子串的位置的话,起始位置是中间位置减去半径再除以2,即(i-p[i])/2,这个是该回文子串在s串里的起始位置,s和t都是从0下标开始放的。

#include<bits/stdc++.h>
using namespace std;
#define ls rt<<1
#define rs (rt<<1)+1
#define PI acos(-1)
#define eps 1e-8
#define ll long long
#define fuck(x) cout<<#x<<"     "<<x<<endl;
typedef pair<int,int> pii;
const int maxn=1e6+10;
int d[4][2]={1,0,-1,0,0,1,0,-1};
//int lowbit(int x){return x&-x;}
//void add(int x,int v){while(x<=n)bit[x]+=v,x+=lowbit(x);}
//int sum(int x){int ans=0;while(x>=1) ans+=bit[x],x-=lowbit(x);return ans;}
char t[maxn];
string Manacher(string s) {
    // Insert '#'
    string t = "$#";
    for (int i = 0; i < s.size(); ++i) {
        t += s[i];
        t += "#";
    }
    // Process t
    vector<int> p(t.size(), 0);
    int mx = 0, id = 0, resLen = 0, resCenter = 0;
    for (int i = 1; i < t.size(); ++i) {
        p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;
        while (t[i + p[i]] == t[i - p[i]]) ++p[i];
        if (mx < i + p[i]) {
            mx = i + p[i];
            id = i;
        }
        if (resLen < p[i]) {
            resLen = p[i];
            resCenter = i;
        }
    }
    return s.substr((resCenter - resLen) / 2, resLen - 1);
}

int main(){

    while(scanf("%s",t)!=EOF)
    {
        cout<<Manacher(t).size()<<endl;
    }
    return 0;
}

马拉车学习博客连接: 
https://www.cnblogs.com/grandyang/p/4475985.html 

posted @ 2019-08-03 00:09  eason99  阅读(86)  评论(0编辑  收藏  举报