Description
母亲节就要到了,小 H 准备送给她一个特殊的项链。这个项链可以看作一个用小写字
母组成的字符串,每个小写字母表示一种颜色。为了制作这个项链,小 H 购买了两个机器。第一个机器可以生成所有形式的回文串,第二个机器可以把两个回文串连接起来,而且第二个机器还有一个特殊的性质:假如一个字符串的后缀和一个字符串的前缀是完全相同的,那么可以将这个重复部分重叠。例如:aba和aca连接起来,可以生成串abaaca或 abaca。现在给出目标项链的样式,询问你需要使用第二个机器多少次才能生成这个特殊的项链。
每个测试数据,输入不超过 5行
每行的字符串长度小于等于 50000
Solution
题意可以转化为最少用多少个回文串覆盖整个序列
可以证明每一次都用极大回文子串不会更劣,那么跑一遍manacher找出所有的极大回文字串
剩下就是最小次数的线段覆盖,这个排序贪心即可
记录i为覆盖到的最左边,枚举线段贪心地选取尽可能靠右的线段即可
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
const int N=200005;
struct line {int l,r;} l[N];
int rad[N];
char str[N];
void manacher(char *ptr,int n) {
static char str[N];
rep(i,1,n) {
str[i*2-1]='#';
str[i*2]=ptr[i];
}
str[n*2+1]='#';
int pos=0,max=0;
rep(i,1,n*2+1) {
if (i<=max) rad[i]=std:: min(rad[pos*2-i],max-i);
else rad[i]=0;
while (i-rad[i]>1&&i+rad[i]<n*2+1&&str[i-rad[i]-1]==str[i+rad[i]+1]) rad[i]++;
if (i+rad[i]>max) {
max=i+rad[i];
pos=i;
}
}
}
bool cmp(line a,line b) {
return a.l<b.l||a.l==b.l&&a.r>b.r;
}
int main(void) {
while (~scanf("%s",str+1)) {
int n=strlen(str+1),tot=0;
manacher(str,n);
rep(i,1,n*2+1) l[++tot]=(line) {i-rad[i],i+rad[i]};
std:: sort(l+1,l+tot+1,cmp);
int ans=0;
for (int i=l[1].r,j=2;i<n*2+1;) {
int max=i;
while (j<=tot&&l[j].l<=i) {
max=std:: max(max,l[j].r);
j++;
}
i=max; ans++;
}
printf("%d\n", ans);
}
return 0;
}