BZOJ_3790_神奇项链_manacher+贪心

BZOJ_3790_神奇项链_manacher+贪心

Description

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

Input

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

Output

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

Sample Input

abcdcba
abacada
abcdef

Sample Output

0
2
5

首先用manacher找出所有极长的回文串。
转化为一堆区间求最小覆盖。
然后由于串可以重叠,直接贪心即可。
 
代码:
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 200050
char w[N];
int a[N],R[N];
struct Line {
    int x,y;
}b[N];
bool cmp(const Line &x,const Line &y) {return x.x<y.x;}
int main() {
    while(scanf("%s",w+1)!=EOF) {
        int n=strlen(w+1);
        int i,tot=0;
        for(i=1;i<=n;i++) a[2*i-1]='$',a[2*i]=w[i];
        n=n<<1|1; a[n]='$';
        int mx=0,lst;
        for(i=1;i<=n;i++) {
            if(i<=mx) R[i]=min(R[lst*2-i],mx-i+1);
            else R[i]=1;
            while(i-R[i]>=1&&i+R[i]<=n&&a[i-R[i]]==a[i+R[i]]) R[i]++;
            if(mx<i+R[i]-1) mx=i+R[i]-1,lst=i;
            b[++tot].x=(i-R[i]+2)>>1; b[tot].y=(i+R[i]-2)>>1;
        }
        sort(b+1,b+tot+1,cmp); n>>=1;
        mx=0; i=1; int ans=0;
        while(mx<n) {
            int tmp=0;
            while(i<=tot&&b[i].x<=mx+1) tmp=max(tmp,b[i].y),i++;
            ans++; mx=tmp;
        }
        printf("%d\n",ans-1);
    }
}

 

posted @ 2018-06-02 19:37  fcwww  阅读(196)  评论(0编辑  收藏  举报