bzoj 3790: 神奇项链
3790: 神奇项链
Description
母亲节就要到了,小 H 准备送给她一个特殊的项链。这个项链可以看作一个用小写字
母组成的字符串,每个小写字母表示一种颜色。为了制作这个项链,小 H 购买了两个机器。第一个机器可以生成所有形式的回文串,第二个机器可以把两个回文串连接起来,而且第二个机器还有一个特殊的性质:假如一个字符串的后缀和一个字符串的前缀是完全相同的,那么可以将这个重复部分重叠。例如:aba和aca连接起来,可以生成串abaaca或 abaca。现在给出目标项链的样式,询问你需要使用第二个机器多少次才能生成这个特殊的项链。
Input
输入数据有多行,每行一个字符串,表示目标项链的样式。
Output
多行,每行一个答案表示最少需要使用第二个机器的次数。
Sample Input
abcdcba
abacada
abcdef
abacada
abcdef
Sample Output
0
2
5
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; }
一念起,天涯咫尺; 一念灭,咫尺天涯。