「BZOJ 2342」「SHOI 2011」双倍回文「Manacher」

题意

\(s_R\)\(s\)翻转后的串,求一个串最长的形如\(ss_Rss_R\)的子串长度

题解

这有一个复杂度明显\(O(n)\)的做法,思路来自网上某篇博客

一个双倍回文串肯定当且仅当本身是一个回文串且左右两边都是回文串

所以对于右边的回文串,到它中心\(i\)的时候,\(manacher\)记录的\(maxr\)一定\(>i\)

如果满足这个条件,那就判断\(i\)\(i\)关于\(mid\)的对称串是否有交点,有交点就说明这是双倍回文串;还要注意不能以字母为中心,因为回文串必须偶数长度

欢迎\(hack\)

#include <algorithm>
#include <cstdio>
using namespace std;

const int N = 1e6 + 10;

int n, f[N];
char c[N >> 1], s[N];

int main() {
    scanf("%d%s", &n, c + 1);
    for(int i = 1; i <= n; i ++) {
        s[i * 2 - 1] = '%';
        s[i * 2] = c[i];
    }
    s[n = n * 2 + 1] = '%';
    int r = 0, mid = 0, ans = 0;
    for(int i = 1; i <= n; i += 2) {
        f[i] = i < r ? min(f[mid + mid - i], r - i) : 1;
        if(i < r && i - f[i] < mid) {
            ans = max(ans, 2 * (i - mid));
        }
        for(; i - f[i] >= 1 && i + f[i] <= n && s[i - f[i]] == s[i + f[i]]; f[i] ++) ;
        if(i + f[i] > r) r = i + f[mid = i];
    }
    printf("%d\n", ans);
    return 0;
}

posted @ 2019-02-14 09:17  hfhongzy  阅读(170)  评论(0编辑  收藏  举报