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
分析:
我们先用manacher计算出所有的回文串
以每个位置为对称轴的回文串就相当于一个小区间
一共有2*n+1个区间
我们需要从中找到尽量少的区间使得整个区间(长度为2*len+1)被覆盖
(manacher中增加的多余字符不影响算法)
这样问题就转化为贪心经典问题之区间覆盖
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=50010;
char ch[N],s[N<<1];
int RL[N<<1],n;
struct node{
int x,y;
};
node po[N<<1];
int init()
{
int len=strlen(ch);
s[0]='@';
for (int i=1;i<=len*2;i+=2)
{
s[i]='#';
s[i+1]=ch[i/2];
}
s[2*len+1]='#';
s[2*len+2]='$';
return 2*len+1;
}
void Manacher()
{
int len=init();
int mx=0,pos=0;
for (int i=1;i<=len;i++)
{
int j=pos*2-i;
if (i<mx) RL[i]=min(mx-i,RL[j]);
else RL[i]=1;
while (s[i-RL[i]]==s[i+RL[i]]) RL[i]++;
if (i+RL[i]>mx)
mx=i+RL[i],pos=i;
po[i].x=i-RL[i]+1; po[i].y=i+RL[i]-1;
}
n=len;
}
int cmp(const node &a,const node &b)
{
if (a.x!=b.x) return a.x<b.x;
else return a.y<b.y;
}
void solve()
{
sort(po+1,po+1+n,cmp);
int R=1,i=1,ans=0;
while (R<n)
{
int mx=0;
while (po[i].x<=R) mx=max(mx,po[i].y),i++;
ans++;
R=mx;
}
printf("%d\n",ans-1);
}
int main()
{
while (scanf("%s",ch)!=EOF)
{
memset(s,0,sizeof(s));
Manacher();
solve();
memset(ch,0,sizeof(ch));
}
return 0;
}