manacher两题:BZOJ2565: 最长双回文串 & [Shoi2011]双倍回文

版权声明:xgc原创文章,未经允许不得转载。 https://blog.csdn.net/xgc_woker/article/details/80215980

BZOJ2565: 最长双回文串

Description
顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。
输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串。


Sample Input
baacaabbacabb


Sample Output
12


你考虑维护一个ex1数组,一个ex2数组。
ex1表示往左扩展最长的回文串。
ex2则反之。


#include <cstdio>
#include <cstring>

using namespace std;
int _min(int x, int y) {return x < y ? x : y;}
int _max(int x, int y) {return x > y ? x : y;}

char ss[110000], now[210000];
int len, p[210000], ex1[110000], ex2[110000];

void manacher() {
    int pos = 0, R = 0;
    for(int i = 1; i <= len; i++) {
        int j = 2 * pos - i;
        if(i <= R) p[i] = _min(p[j], R - i);
        else p[i] = 1;
        while(1 <= i - p[i] && i + p[i] <= len && now[i - p[i]] == now[i + p[i]]) p[i]++;
        if(i + p[i] - 1 > R) pos = i, R = i + p[i] - 1;
    }
}

int main() {
    scanf("%s", ss + 1);
        len =strlen(ss + 1);
    for(int i = 1; i <= len ; i++) {
        now[i * 2 - 1] = '#';
        now[i * 2] = ss[i];
    }
    len = len * 2 + 1;
    now[len] = '#';
    manacher();
    int ans = 0;
    for(int i = 1; i <= len / 2; i++) ex1[i] = ex2[i] = 1;
    for(int i = 1; i <= len; i++) {
        ex1[(i - p[i] + 2) / 2] = _max(ex1[(i - p[i] + 2) / 2], p[i] - 1);
        ex2[(i + p[i] - 1) / 2] = _max(ex2[(i + p[i] - 1) / 2], p[i] - 1);
    }
    for(int i = 1; i <= len / 2; i++) ex1[i] = _max(ex1[i], ex1[i - 1] - 2);
    for(int i = len / 2; i >= 1; i--) ex2[i] = _max(ex2[i], ex2[i + 1] - 2);
    for(int i = 2; i <= len / 2; i++) ans = _max(ans, ex2[i - 1] + ex1[i]);
    printf("%d\n", ans);
    return 0;
}

[Shoi2011]双倍回文

Description
给出一个字符串,求出一个最长的子串满足不但由两个回文子串组成,而且本身也是一个回文串,且这两个回文子串不重叠,并且这两个回文子串长度为偶数,也就是说原子串的长度一定是4的倍数


Sample Input
16
ggabaabaabaaball


Sample Output
12


你枚举一个回文中心。
然后你设这个回文中心扩展最多到s。
你从s/2那个位置开始枚举,遇到合适的就break。
这样其实是不能出数据卡的。。。


#include <cstdio>
#include <cstring>

using namespace std;
int _min(int x, int y) {return x < y ? x : y;}
int _max(int x, int y) {return x > y ? x : y;}

char ss[510000], now[1100000];
int len, p[1100000];

void manacher() {
    int pos = 0, R = 0;
    for(int i = 1; i <= len; i++) {
        int j = 2 * pos - i;
        if(i <= R) p[i] = _min(p[j], R - i);
        else p[i] = 1;
        while(1 <= i - p[i] && i + p[i] <= len && now[i - p[i]] == now[i + p[i]]) p[i]++;
        if(i + p[i] - 1 > R) pos = i, R = i + p[i] - 1;
    }
}

int main() {
    scanf("%d", &len);
    scanf("%s", ss + 1);
    for(int i = 1; i <= len ; i++) {
        now[i * 2 - 1] = '#';
        now[i * 2] = ss[i];
    }
    len = len * 2 + 1;
    now[len] = '#';
    manacher();
    int ans = 0;
    for(int i = 3; i < len; i += 2) {
        int uu = i - p[i] / 2;
        if(uu % 2 == 0) uu++;
        for(int j = uu; j < i - 2; j += 2) {
            if(j + p[j] - 1 >= i) {
                ans = _max(ans, (i - j) * 2);
                break;
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xgc_woker/article/details/80215980
今日推荐