bzoj3790 神奇项链

Description

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

Input

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

Output

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

Sample Input

abcdcba 
abacada 
abcdef

Sample Output

0
2
5

Hint

每个测试数据,输入不超过 5行 
每行的字符串长度小于等于 50000 
 
 
manacher+贪心
 
manacher:一种线性时间求回文串长度的算法(右转Baidu)
 
用manacher处理出以某个点开始的最长回文串长度,问题就转变成区间覆盖问题
用贪心跑一遍即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
using namespace std;
template <typename T> inline T min(T &a,T &b) {return a<b ?a:b;}
template <typename T> inline T max(T &a,T &b) {return a>b ?a:b;}
char a[1000005],b[1000005];
int p[1000005],f[1000005];
int main(){
    while(scanf("%s",a)!=EOF){
        memset(f,0,sizeof(f));
        int len=strlen(a),n=0,id=0,mx=-1,last,mxd,ans=0;
        for(int i=0;i<len;++i) b[n++]='#',b[n++]=a[i];
        b[n++]='#';
        for(int i=0;i<n;++i){
            if(i<mx) p[i]=min(p[id*2-i],mx-i+1);
            else p[i]=1;
            while(i-p[i]>=0&&i+p[i]<n&&b[i-p[i]]==b[i+p[i]]) ++p[i];
            if(i+p[i]-1>mx) mx=i+p[i]-1,id=i;
            f[i-p[i]+1]=i+p[i]-1; //处理出从点i-p[i]+1开始的最长回文串长度
        }last=mxd=f[0]+2;
        for(int i=0;i<n;i+=2){ //贪心
            if(i==last) last=mxd,++ans;
            mxd=max(mxd,f[i]+2);
        }printf("%d\n",ans);
    }return 0;
}

 

posted @ 2018-09-26 22:19  kafuuchino  阅读(108)  评论(0编辑  收藏  举报