BZOJ 3790 神奇项链 (manacher)

Description

母亲节就要到了,小 H 准备送给她一个特殊的项链。这个项链可以看作一个用小写字
母组成的字符串,每个小写字母表示一种颜色。为了制作这个项链,小 H 购买了两个机器。第一个机器可以生成所有形式的回文串,第二个机器可以把两个回文串连接起来,而且第二个机器还有一个特殊的性质:假如一个字符串的后缀和一个字符串的前缀是完全相同的,那么可以将这个重复部分重叠。例如:aba和aca连接起来,可以生成串abaaca或 abaca。现在给出目标项链的样式,询问你需要使用第二个机器多少次才能生成这个特殊的项链。

Input

输入数据有多行,每行一个字符串,表示目标项链的样式。

Output

多行,每行一个答案表示最少需要使用第二个机器的次数。

Sample Input

abcdcba

abacada

abcdef

Sample Output

0

2

5

HINT

每个测试数据,输入不超过 5行

每行的字符串长度小于等于 50000

题解

首先跑manacher然后再跑贪心

代码

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

const int N = 100010;

struct Node {
    int l, r;
} a[N];
char s[N], t[N];
int ans, tot, now, pal[N];

bool cmp(const Node &a, const Node &b) {
     return a.l < b.l || (a.l == b.l && a.r < b.r);
}

void manacher() {
    int len = strlen(t);
    for(int i = 0; i < len; i ++)
        s[++ tot] = '#', s[++ tot] = t[i];
    s[0] = '+', s[++ tot] = '#', s[tot + 1] = '-';
    int id = 0, mx = 0;
    for(int i = 1; i <= tot; i ++) {
        pal[i] = mx >= i ? min(pal[id * 2 - i], mx - i + 1) : 1;
        while(s[i + pal[i]] == s[i - pal[i]]) pal[i] ++;
        if(pal[i] + i - 1 > mx)
            mx = pal[i] + i - 1, id = i;
        a[i].l = i - pal[i] + 1, a[i].r = i + pal[i] - 1;
    }
}

void clear() {
    ans = tot = 0, now = 1;
    memset(a, 0, sizeof(a));
    memset(pal, 0, sizeof(pal));
}

int main() {
    while(scanf("%s", &t) != EOF) {
        clear();
        manacher();
        sort(a + 1, a + tot + 1, cmp);
        for(int i = 1; i <= tot; i ++) {
            int x = 0;
            if(a[i].r <= now) continue;
            for(register int j = i; j <= tot; j ++) {
                if(a[j].l <= now && a[j].r >= a[x].r) x = j;
                else if(a[j].l > now) break;
            }
            now = a[x].r, ans ++;
            if(now >= tot) break;
        }
        printf("%d\n", ans - 1);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值