BZOJ 3790 神奇项链(manacher+贪心)
3790: 神奇项链
Time Limit: 10 Sec Memory Limit: 64 MBDescription
母亲节就要到了,小 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
题解
先用manacher算出每一个位置的最大回文半径,再算出每一个点对应的回文区间。
然后就是一个用最少区间覆盖整个区间的贪心。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 const int N=200000; 8 char s[N],str[N]; 9 int len,p[N]; 10 struct Line{ 11 int l,r; 12 }c[N]; 13 void init(){ 14 str[0]=str[1]='#'; 15 for(int i=1;i<=len;i++){ 16 str[i<<1]=s[i]; 17 str[(i<<1)+1]='#'; 18 } 19 len=(len<<1)+1; 20 } 21 void manacher(){ 22 int mx=0,id; 23 for(int i=1;i<=len;i++){ 24 if(mx>i)p[i]=min(p[id-(i-id)],p[id]+id-i); 25 else p[i]=1; 26 while(str[i+p[i]]==str[i-p[i]])p[i]++; 27 if(i+p[i]>mx){ 28 id=i; 29 mx=i+p[i]; 30 } 31 } 32 } 33 bool cmp(Line a,Line b){ 34 return a.l<b.l; 35 } 36 void work(){ 37 sort(c+1,c+1+len,cmp); 38 int now=1,tmp=0,ans=0; 39 for(int i=1;i<=len;i++){ 40 if(c[i].l<=now){ 41 tmp=max(tmp,c[i].r); 42 } 43 else{ 44 now=tmp+1; 45 if(now>len)break; 46 ans++; 47 i--; 48 } 49 } 50 printf("%d\n",ans); 51 } 52 int main(){ 53 while(scanf("%s",s+1)!=EOF){ 54 len=strlen(s+1); 55 init(); 56 manacher(); 57 for(int i=1;i<=len;i++){ 58 c[i].l=i-p[i]+1; 59 c[i].r=i+p[i]-1; 60 } 61 work(); 62 } 63 return 0; 64 }