暑假訓練round2 D: 好序列(Manacher)

Problem 1061: 好序列


Time Limits:  1000 MS   Memory Limits:  65536 KB

64-bit interger IO format:  %lld   Java class name:  Main


Description

楊神覺得好的序列需要符合這兩個條件
1.這段序列可以平均分成三段,第一段和第三段相同
2.第二段與第一段相反
給你一個由n個非負整數組成的序列,問連續子序列是好序列時,該連續子序列的長度是多少。

Input

第一行爲t 代表t組測試數據
第二行爲n ( 1 <= n <= 100000)代表序列由n個非負整數組成
第三行爲n個數 (ai < 100000)

 

Output


開始爲"Case #i: " 後面跟着一個整數,代表最長的連續子序列爲好序列的長度

Sample Input

1
10
2 3 4 4 3 2 2 3 4 4

Output for Sample Input

Case #1: 9

比賽的時候只知道用manacher,之後就感覺下標處理起來麻煩就沒做了……,正確解法是枚舉i的對稱點i+p[i]-1,再從對稱點再往回掃一遍,看看存不存在也能往回覆蓋至i點,有的話就記錄[當前點-i]爲1.5段的長度即可。

代碼:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define INF 0x3f3f3f3f
#define MM(x,y) memset(x,y,sizeof(x))
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
typedef pair<int,int> pii;
typedef long long LL;
const double PI=acos(-1.0);
const int N=100010;
int arr[N],p[N*2];
int s[N*2];
int n;
void manacher()
{
	MM(p,0);
	MM(s,0);
	int i, len=0;
	s[len++]=-2;
	s[len++]=-1;
	for (i=0; i<n; i++)
	{
		s[len++]=arr[i];
		s[len++]=-1;
	}
	int mx=0, idd=0;
	for (i=0; i<len; i++)
	{
		if(mx>i)
			p[i]=min(p[2*idd-i],mx-i);
		else
			p[i]=1;
		while (s[i+p[i]]==s[i-p[i]])
			p[i]++;
		if(i+p[i]>mx)
		{
			mx=p[i]+i;
			idd=i;
		}
	}
}
int main(void)
{
	int tcase, i, j, cnt=0;
	scanf("%d",&tcase);
	while (tcase--)
	{
		MM(arr,0);
		scanf("%d",&n);
		for (i=0; i<n; i++)
			scanf("%d",&arr[i]);
		manacher();
		int ans=0;
		for (i=1; i<2*n+2; i+=2)
		{
			for (j=i+p[i]-1; j-i>ans; j-=2)//往回遍歷
			{
				if(j-(p[j]-1)<=i)
				{
					if(j-i>ans)
					{
						ans=j-i;
						break;
					}
				}	
			}
		}					
		printf("Case #%d: %d\n",++cnt,3*(ans>>1));
	}
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章