bzoj3790 神奇项链 manacher+贪心

Description


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

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

Solution


题意可以转化为最少用多少个回文串覆盖整个序列
可以证明每一次都用极大回文子串不会更劣,那么跑一遍manacher找出所有的极大回文字串
剩下就是最小次数的线段覆盖,这个排序贪心即可
记录i为覆盖到的最左边,枚举线段贪心地选取尽可能靠右的线段即可

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))

const int N=200005;

struct line {int l,r;} l[N];

int rad[N];

char str[N];

void manacher(char *ptr,int n) {
    static char str[N];
    rep(i,1,n) {
        str[i*2-1]='#';
        str[i*2]=ptr[i];
    }
    str[n*2+1]='#';
    int pos=0,max=0;
    rep(i,1,n*2+1) {
        if (i<=max) rad[i]=std:: min(rad[pos*2-i],max-i);
        else rad[i]=0;
        while (i-rad[i]>1&&i+rad[i]<n*2+1&&str[i-rad[i]-1]==str[i+rad[i]+1]) rad[i]++;
        if (i+rad[i]>max) {
            max=i+rad[i];
            pos=i;
        }
    }
}

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

int main(void) {
    while (~scanf("%s",str+1)) {
        int n=strlen(str+1),tot=0;
        manacher(str,n);
        rep(i,1,n*2+1) l[++tot]=(line) {i-rad[i],i+rad[i]};
        std:: sort(l+1,l+tot+1,cmp);
        int ans=0;
        for (int i=l[1].r,j=2;i<n*2+1;) {
            int max=i;
            while (j<=tot&&l[j].l<=i) {
                max=std:: max(max,l[j].r);
                j++;
            }
            i=max; ans++;
        }
        printf("%d\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值