Codeforces 1326D2 - Prefix-Suffix Palindrome (Hard version) (Manacher算法)

Description

思路

先求出最长的回文的前后缀,然后求每个最长回文区间能不能和前缀或后缀接起来,取接起来后长度最大的那个。
基本就是纯的马拉车算法了。就是要注意边界处理的细节,很容易出问题。我把前后缀的位置处理为开区间,回文区间为闭区间。这样边界相等就可以接起来。详见代码。

#include <bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
 
char ss[N];
string s;
string ans;
int len[N];
 
void mana() { //马拉车
    s.clear();
    ans.clear();
    s.push_back('$');
    s.push_back('#');
    for(int i = 0; ss[i]; i++) {
        s.push_back(ss[i]);
        s.push_back('#');
    }
 
    int a = 1, p = 1;
    for(int i = 1; i < s.size(); i++) {
        if(i < p && len[2 * a - i] < p - i) len[i] = len[2 * a - i];
        else {
            int l = p - i;
            while(i + l < s.size() && s[i + l] == s[i - l]) l++;
            len[i] = l;
            a = i;
            p = i + l;
        }
    }
    //for(int i = 0; ss[i]; i++) cout << len[(i + 1) * 2] / 2 << " ";
}
 
int main() {
    ios::sync_with_stdio(false);
    int t;
    cin >> t;
    while(t--) {
        cin >> ss;
        mana();
        int p1 = 1, p2 = s.size() - 1;
        while(p1 < p2 && s[p1] == s[p2]) p1++, p2--;
        if(p1 >= p2) {cout << ss << endl; continue;}
        int mx = 0, mxp, fx;
        for(int i = 1; i < s.size(); i++) {
            int l = i - len[i] + 1;
            int r = i + len[i] - 1; //l, r为回文区间(闭区间)
            if(l > p1 && r < p2) continue;  //[l, r]与前后缀都接不起来
            if(l - 1 < s.size() - r - 1) {  //[l, r]离前后边界哪个就接到哪个前或后缀
                if(2 * (i - 1) + 1 > mx) {
                    mxp = i;
                    mx = 2 * (i - 1) + 1;
                    fx = 0;
                }
            }  else {
                if((s.size() - i - 1) * 2 + 1 > mx) {
                    mxp = i;
                    mx = (s.size() - i - 1) * 2 + 1;
                    fx = 1;
                }
            }
        }
        if(fx == 0) { //接到不同前后缀方向不同
            int d = (mx - 1) / 2;
            for(int i = mxp - d; i < mxp; i++) ans.push_back(s[i]);
            for(int i = mxp; i >= mxp - d; i--) ans.push_back(s[i]);
            for(char ch : ans) if(ch != '#') cout << ch;
            cout << endl;
        } else {
            int d = (mx - 1) / 2;
            for(int i = mxp + d; i > mxp; i--) ans.push_back(s[i]);
            for(int i = mxp; i <= mxp + d; i++) ans.push_back(s[i]);
            for(char ch : ans) if(ch != '#') cout << ch;
            cout << endl;
        }
    }
    
    
}
posted @ 2020-04-03 14:15  limil  阅读(177)  评论(0编辑  收藏  举报