吉哥又想出了一个新的完美队形游戏!
假设有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]。
现在吉哥想知道:最多能选出多少人组成新的完美队形呢?
假设有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]。
现在吉哥想知道:最多能选出多少人组成新的完美队形呢?
每组数据首先是一个整数n(1 <= n <= 100000),表示原先队形的人数,接下来一行输入n个整数,表示原队形从左到右站的人的身高(50 <= h <= 250,不排除特别矮小和高大的)。
2 3 51 52 51 4 51 52 52 51
3 4
题目大意就是求一个最长回文串,回文串的前一半满足非严格单调递增,后一半满足非严格单调递减
将马拉车的模板改一下,具体看代码
代码
#include <iostream>
#include <cstdio>
#include<cstring>
#include <algorithm>
using namespace std;
const int maxn=100005;
int str[maxn];//原字符串
int tmp[maxn<<1];//转换后的字符串
int Len[maxn<<1];
//转换原始串
int N;
int INIT(int *st)
{
int i,len=N;
tmp[0]=-2;//字符串开头增加一个特殊数字,防止越界
tmp[1]=-1;
for(i=0;i<len;i++)
{
tmp[(i+1)<<1]=str[i];
tmp[((i+1)<<1)+1]=-1;
}
tmp[2*len+1]=-1;
tmp[2*len+2]=-3;//字符串结尾加一个数字,防止越界
tmp[2*len+3]=0;
return 2*len+1;//返回转换字符串的长度
}
//Manacher算法计算过程
int MANACHER(int *st,int len)
{
memset(Len,0,sizeof Len);
int ans=0,pos=0;
for(int i=1;i<=len;i++)
{
bool label=true;
if(Len[pos]+pos>i)
Len[i]=min(Len[2*pos-i],Len[pos]+pos-i);
else
Len[i]=1;
while(st[i-Len[i]]==st[i+Len[i]]&&label)
{
if(st[i-Len[i]]<0)//若为插入数字
Len[i]++;
else if(st[i-Len[i]]<=st[i+Len[i]-2])
Len[i]++;
else//不满足单调性,则退出while循环
label=false;
}
if(Len[i]+i>pos+Len[pos])
{
pos=i;
}
ans=max(ans,Len[i]);
}
return ans-1;//返回Len[i]中的最大值-1即为原串的最长回文子串额长度
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&N);
for(int i=0;i<N;i++)
scanf("%d",&str[i]);
int tnum=INIT(str);
printf("%d\n",MANACHER(tmp,tnum));
}
return 0;
}