BZOJ 3790 神奇项链 Manacher 树状数组

几个月没写manacher忘干净了。。。

将一些回文串直接连接或前、后缀重复部分完全重叠,产生了新的字符串,问该字符串的连接次数。

如abacada
考虑求出所有极长回文串。
即a[1..1,3..3,5..5,7..7],b[2..2,6..6],c[4..4],aba[1..3],aca[3..5],ada[5..7]
发现这些回文串按照其位置放置将区间完整覆盖的方案即我们所求。
也就是说,从一堆线段中,挑选一些,使这些线段完整地覆盖区间[1..7]
如果按右端点排序,那么对于每个线段i,覆盖到r[i]的可行方案,是之前存在一个方案,覆盖到l[i]-1~r[i]间,因此表示方案为其覆盖到的右端点,每次查询l[i]-1~r[i]间的方案的最小使用线段树,也就是单点修改区间查询,树状数组即可。。。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define FOR(i,j,k) for(i=j;i<=k;++i)
const int inf = 0x3f3f3f3f, N = 100002;
int c[N], n, k, p[N]; char s[N], a[2 * N];
int query(int i) {
    if (!i) return 0;
    int s = inf;
    for (; i <= n; i += i & -i) s = min(s, c[i]);
    return s;
}

void update(int i, int x) {
    for (; i; i -= i & -i) c[i] = min(c[i], x);
}

struct Data { int a, b; } d[N];
bool operator< (const Data &a, const Data &b) { return a.b < b.b; }

void manacher() {
    int mx = 0, id, m = 2 * n + 1, i, l, r;
    for (i = 1; i <= n; ++i) {
        a[i * 2] = s[i];
        a[i * 2 + 1] = '#';
    }
    a[0] = '&'; a[m + 1] = '^'; a[1] = '#';
    for (i = 1; i <= m; ++i) {
        if (mx > i) p[i] = min(mx - i, p[2 * id - i]);
        else p[i] = 1;
        while (a[i - p[i]] == a[i + p[i]]) ++p[i];
        if (i + p[i] > mx) mx = i + p[i], id = i;
        l = (i - p[i]) / 2 + 1; r = (i + p[i]) / 2 - 1;
        if (l <= r) d[++k] = (Data) { l, r };
    }
}



int main() {
    int ans, i, x;
    while (scanf("%s", s + 1) != EOF) {
        n = strlen(s + 1); ans = inf; k = 0;
        FOR(i,0,n) c[i] = inf;
        manacher();
        sort(d + 1, d + k + 1);
        FOR(i,1,k) {
            x = query(d[i].a - 1) + 1;
            update(d[i].b, x);
            if (d[i].b == n) ans = min(ans, x);
        }
        printf("%d\n", ans - 1);
    }
    return 0;
}

3790: 神奇项链

Description

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

Input

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

Output

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

Sample Input

abcdcba
abacada
abcdef

Sample Output

0
2
5

HINT

每个测试数据,输入不超过 5行
每行的字符串长度小于等于 50000

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值