您的位置:首页 > 其它

【bzoj3790】神奇项链 Manacher+贪心

2017-05-03 17:32 211 查看
原文地址:http://www.cnblogs.com/GXZlegend/p/6803032.html

题目描述

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

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

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

abcdcba

abacada

abcdef

样例输出

0

2

5

题解

Manacher+贪心,时间复杂度瓶颈在于排序

首先易知用于覆盖的回文串一定是极长回文串,那么可以先用Manacher求出所有极长回文串。

这样就将问题转化为线段覆盖问题:n条线段用于覆盖,可以重叠,求最少用多少条线段能够覆盖整个[1,n]。

按l排序,贪心就可以了。

依旧是有O(n)的优秀算法

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 250010
using namespace std;
struct data
{
int l , r;
}a
;
char str
, tmp[N << 1];
int n , p[N << 1];
bool cmp(data a , data b)
{
return a.l < b.l;
}
int main()
{
while(scanf("%s" , str + 1) != EOF)
{
n = strlen(str + 1);
int i , mx = 0 , last , tot = 0 , pl = 0 , ans = 0;
tmp[0] = '0';
for(i = 1 ; i <= n ; i ++ ) tmp[i * 2 - 1] = '#' , tmp[i * 2] = str[i];
n = n * 2 + 1 , tmp
= '#';
for(i = 1 ; i <= n ; i ++ )
{
if(mx >= i) p[i] = min(p[last * 2 - i] , mx - i + 1);
else p[i] = 1;
while(tmp[i - p[i]] == tmp[i + p[i]]) p[i] ++ ;
if(mx < i + p[i] - 1) mx = i + p[i] - 1 , last = i;
a[++tot].l = (i - p[i] + 2) / 2 , a[tot].r = (i + p[i] - 2) / 2;
}
sort(a + 1 , a + tot + 1 , cmp);
n /= 2;
i = 1;
while(pl < n)
{
mx = 0;
while(a[i].l <= pl + 1) mx = max(mx , a[i].r) , i ++ ;
ans ++ , pl = mx;
}
printf("%d\n" , ans - 1);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: