bzoj 3790: 神奇项链

3790: 神奇项链

Description

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

Input

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

Output

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

Sample Input

abcdcba
abacada
abcdef

Sample Output

0
2
5

HINT

每个测试数据,输入不超过 5行 
每行的字符串长度小于等于 50000 
 
题解:
 
先o(n)预处理出每个回文区间,接下来题目就等价与在这些区间里找出最少的区间来覆盖整个串。
 
DP或者贪心。。数据有点水。。没优化的DP都200ms过了。。。。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=50005;
struct node
{
    int a,b;
}q[N<<1];
char a[N],s[N<<1];
int n,i,j,x,p[N<<1],f[N<<1];
bool cmp(const node&x,const node&y)
{
    return x.b<y.b;
}
int main()
{
    while(scanf("%s",a+1)!=EOF)
    {
        n=strlen(a+1);
        for(i=1;i<=2*n+1;i++)
            if(i&1) s[i]='#';else s[i]=a[i/2];
        s[0]='.';s[n*2+2]='*';
        for(i=1;i<=2*n+1;i++) p[i]=0,f[i]=1e9;
        x=0;
        for(i=1;i<=2*n+1;i++)
        {
            if(x+p[x]>i) p[i]=min(p[x*2-i],x+p[x]-i);else
            p[i]=1;
            while(s[i-p[i]]==s[i+p[i]]) p[i]++;
            if(i+p[i]>x+p[x]) x=i;
        }
        for(i=1;i<=2*n+1;i++)
            q[i].a=i-p[i]+1,q[i].b=i+p[i]-1;
        sort(q+1,q+2*n+2,cmp);
        x=1;
        for(i=1;i<=2*n+1;i++)
        {
            while(q[x].b==i)
            {
                for(j=q[x].a-1;j<i;j++) f[i]=min(f[i],f[j]+1);
                x++;
            }
        }
        cout<<f[n*2+1]-1<<endl;
    }
    return 0;
}

  

posted @ 2016-07-19 18:42  lwq12138  阅读(195)  评论(0编辑  收藏  举报