bzoj3790 神奇项链

3790: 神奇项链

Time Limit: 10 Sec   Memory Limit: 64 MB
Submit: 303   Solved: 149
[ Submit][ Status][ Discuss]

Description

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

Input

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

Output

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

Sample Input

abcdcba
abacada
abcdef

Sample Output

0
2
5

HINT

每个测试数据,输入不超过 5行 

每行的字符串长度小于等于 50000 



manacher+DP+线段树

首先用manacher,求出所有回文串。

于是问题转化为:给定一些线段,问最少几条线段可以覆盖整个区间。

线段树优化DP搞定。




#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 100005
#define inf 1000000000
using namespace std;
int n,tot,f[maxn],mn[maxn*4];
char s[maxn],ss[maxn];
struct data{int x,y;}p[maxn];
inline bool cmp(data a,data b)
{
	return a.y==b.y?a.x<b.x:a.y<b.y;
}
void manacher()
{
	int mx=0,id=0;
	F(i,1,n)
	{
		if (mx>i) f[i]=min(mx-i,f[id*2-i]);
		else f[i]=0;
		while (s[i+f[i]]==s[i-f[i]]) f[i]++;
		if (i+f[i]>mx) mx=i+f[i],id=i;
	}
}
void build(int k,int l,int r)
{
	mn[k]=inf;
	if (l==r) return;
	int mid=(l+r)>>1;
	build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
void pushup(int k)
{
	mn[k]=min(mn[k<<1],mn[k<<1|1]);
}
void change(int k,int l,int r,int pos,int val)
{
	if (l==r){mn[k]=min(mn[k],val);return;}
	int mid=(l+r)>>1;
	if (pos<=mid) change(k<<1,l,mid,pos,val);
	else change(k<<1|1,mid+1,r,pos,val);
	pushup(k);
}
int query(int k,int l,int r,int L,int R)
{
	if (l==L&&r==R) return mn[k];
	int mid=(l+r)>>1;
	if (R<=mid) return query(k<<1,l,mid,L,R);
	else if (L>mid) return query(k<<1|1,mid+1,r,L,R);
	else return min(query(k<<1,l,mid,L,mid),query(k<<1|1,mid+1,r,mid+1,R));
}
int main()
{
	while (scanf("%s",ss+1)!=EOF)
	{
		int len=strlen(ss+1);
		n=len<<1|1;
		s[0]='*';s[1]='#';s[n+1]='&';
		F(i,1,n) s[i<<1]=ss[i],s[i<<1|1]='#';
		manacher();
		tot=0;
		F(i,1,n) if (s[i]!='#'||f[i]>1) p[++tot]=(data){(i-f[i])/2+1,(i+f[i])/2-1};
		sort(p+1,p+tot+1,cmp);
		int tmp=0;
		F(i,1,tot) if (!tmp||p[tmp].y!=p[i].y) p[++tmp]=p[i];
		tot=tmp;
		n=len;
		F(i,1,n) f[i]=inf;
		build(1,0,n);change(1,0,n,0,0);
		F(i,1,tot)
		{
			f[p[i].y]=min(f[p[i].y],query(1,0,n,p[i].x-1,p[i].y-1)+1);
			change(1,0,n,p[i].y,f[p[i].y]);
		}
		printf("%d\n",f[n]-1);
	}
	return 0;
}


你可能感兴趣的:(字符串,dp,线段树,Manacher)