1. 程式人生 > >BZOJ3790神奇項鏈——manacher+貪心

BZOJ3790神奇項鏈——manacher+貪心

math its while 表示 ans 題目 bzoj3 最長回文串 queue

題目描述

母親節就要到了,小 H 準備送給她一個特殊的項鏈。這個項鏈可以看作一個用小寫字 母組成的字符串,每個小寫字母表示一種顏色。為了制作這個項鏈,小 H 購買了兩個機器。第一個機器可以生成所有形式的回文串,第二個機器可以把兩個回文串連接起來,而且第二個機器還有一個特殊的性質:假如一個字符串的後綴和一個字符串的前綴是完全相同的,那麽可以將這個重復部分重疊。例如:aba和aca連接起來,可以生成串abaaca或 abaca。現在給出目標項鏈的樣式,詢問你需要使用第二個機器多少次才能生成這個特殊的項鏈。

輸入

輸入數據有多行,每行一個字符串,表示目標項鏈的樣式。

輸出

多行,每行一個答案表示最少需要使用第二個機器的次數。

樣例輸入

abcdcba
abacada
abcdef

樣例輸出

0
2
5

提示

每個測試數據,輸入不超過 5行 每行的字符串長度小於等於 50000 將每個回文串看作一個線段,那麽問題就變成至少多少個線段能將區間全部覆蓋。用manacher求一下以每個位置為中心的最長回文串,將其視為一個線段然後按左端點排序貪心選線段即可。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
char s[100010];
int len[100010];
int n;
int mx,num;
struct miku
{
	int l,r;
}a[100010];
bool cmp(miku a,miku b)
{
	return a.l<b.l;
}
int main()
{
	while(scanf("%s",s+1)!=EOF)
	{
		n=strlen(s+1);
		for(int i=n;i>=1;i--)
		{
			s[i<<1]=s[i];
			s[i<<1|1]=‘&‘;
		}
		n=n<<1|1;
		s[0]=‘%‘;
		s[1]=‘&‘;
		s[n+1]=‘^‘;
		mx=0,num=0;
		for(int i=1;i<=n;i++)
		{
			len[i]=mx>i?min(len[num*2-i],mx-i):1;
			while(s[i+len[i]]==s[i-len[i]])
			{
				len[i]++;
			}
			if(mx<i+len[i])
			{
				mx=i+len[i];
				num=i;
			}
		}
		for(int i=1;i<=n;i++)
		{
			a[i].l=i-len[i]+1;
			a[i].r=i+len[i]-1;
		}
		sort(a+1,a+1+n,cmp);
		int r=0,ans=0,i=1;
		while(i<=n)
		{
			int sum=0;
			while(a[i].l-1<=r&&i<=n)
			{
				sum=max(sum,a[i].r);
				i++;
			}
			ans++;
			r=sum;
			if(r==n)
			{
				break;
			}
		}
		printf("%d\n",ans-1);
	}
}

BZOJ3790神奇項鏈——manacher+貪心