HDU 4513吉哥系列故事——完美队形II Manacher

HDU 4513吉哥系列故事——完美队形II Manacher

题意

吉哥又想出了一个新的完美队形游戏!
假设有n个人按顺序站在他的面前,他们的身高分别是h[1], h[2] ... h[n],吉哥希望从中挑出一些人,让这些人形成一个新的队形,新的队形若满足以下三点要求,则就是新的完美队形:

  1. 挑出的人保持原队形的相对顺序不变,且必须都是在原队形中连续的;
  2. 左右对称,假设有m个人形成新的队形,则第1个人和第m个人身高相同,第2个人和第m-1个人身高相同,依此类推,当然如果m是奇数,中间那个人可以任意;
  3. 从左到中间那个人,身高需保证不下降,如果用H表示新队形的高度,则H[1] <= H[2] <= H[3] .... <= H[mid]

现在吉哥想知道:最多能选出多少人组成新的完美队形呢?

解题思路

看到这里序列的特殊要求实际上不就是个回文串嘛,那肯定就是Manacher算法了。

关键是如何处理大小关系呢,这里是在模板中加了一些判断就可以解决:

  1. 中间插入的不再是字符,而是数字,这里我们插入0x3f3f3f3f这个来进行代替。
  2. 在判断完对称的数字相等之后还要判断是否小于,这里需要知道两个实际的数之间有我们插的数,这个需要注意。
  3. 其他细节看代码。

代码实现

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e5+7;
int num[maxn], tmp[maxn<<1];
int p[maxn<<1]; 
int t, n;
void init()
{
	tmp[0]=inf+1;
	for(int i=1; i<=2*n; i+=2)
	{
		tmp[i] = inf;
		tmp[i+1] = num[i>>1];
	}
	tmp[(n<<1)+1]=inf;
	tmp[(n<<1)+2]=inf+1;
}
int manacher(int *st, int len)
{
	int mx=0, ans=0, po=0;
	for(int i=1; i<=len; ++i)
	{
		if(mx > i)
			p[i]=min( mx-i, p[ (po<<1) - i ] );
		else 
			p[i]=1;
		while(st[ i - p[i]] ==st[ i + p[i]] )
		{
			if( st[ i-p[i] ] == inf)
				p[i]++;
			else if(st[ i-p[i] ] <= st[ i-p[i]+2 ])
				p[i]++;
			else break;
		}
		if(p[i]+i>mx)
		{
			mx=p[i]+i;
			po=i;
		}
		ans=max(ans, p[i]);
	}
	return ans-1;
}
int main()
{
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d", &n);
		for(int i=0; i<n; i++)
			scanf("%d", &num[i]);
		init();
//		for(int i=1; i<=2*n+1; i++)
//			printf("%d ", tmp[i]);
//		printf("
");
		int ans=manacher(tmp, n*2+1);
		printf("%d
", ans);
	}
	return 0;
 } 
原文地址:https://www.cnblogs.com/alking1001/p/12248537.html