Hotaru Ichijou recently is addicated to math problems. Now she is playing with N-sequence.
Let’s define N-sequence, which is composed with three parts and satisfied with the following condition:
- the first part is the same as the thrid part,
- the first part and the second part are symmetrical.
for example, the sequence 2,3,4,4,3,2,2,3,4 is a N-sequence, which the first part 2,3,4 is the same as the thrid part 2,3,4, the first part 2,3,4 and the second part 4,3,2 are symmetrical.
Give you n positive intergers, your task is to find the largest continuous sub-sequence, which is N-sequence.
Input
There are multiple test cases. The first line of input contains an integer T(T<=20), indicating the number of test cases.
For each test case:
the first line of input contains a positive integer N(1<=N<=100000), the length of a given sequence
the second line includes N non-negative integers ,each interger is no larger than 109 , descripting a sequence.
Output
Each case contains only one line. Each line should start with “Case #i: ”,with i implying the case number, followed by a integer, the largest length of N-sequence.
We guarantee that the sum of all answers is less than 800000.
Sample Input
1
10
2 3 4 4 3 2 2 3 4 4
Sample Output
Case #1: 9
题意: 寻找一个最长子串,满足这个子串平均分成三部分,可以满足第一部分和第二部分对称,第一部分和第三部分相同
思路:
翻译一下就是第二部分和第三部分对称。
设f[i]为以i为中心回文长度的一半(代码中向上取整,此处向下取整)
数列翻倍后,这三个部分就多了2个中心点。manacher判出回文串的长度。
以i为中心向右(左)拓展x长度,x ≤ p[i]。
这两部分满足对称。
假设f[x + i] 大于等于x,就意味着第二部分和第三部分回文。
取最大即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 3e5 + 7;
int a[maxn],b[maxn],p[maxn];
int n,l;
void manacher()
{
int id = 0,mx = -1;
for(int i = 1;i < l;i++)
{
if(id + mx > i)p[i] = min(p[2 * id - i],id + mx - i);
while(i - p[i] >= 1 && i + p[i] <= l && a[i - p[i]] == a[i + p[i]])p[i]++;
if(id + mx < i + p[i])
{
id = i;
mx = p[i];
}
}
}
void init()
{
l = 0;
memset(p,0,sizeof(p));
for(int i = 1;i <= n;i++)
{
a[++l] = -1;
a[++l] = b[i];
}
a[++l] = -1;
}
int main()
{
int T;scanf("%d",&T);
int kase = 0;
while(T--)
{
scanf("%d",&n);
for(int i = 1;i <= n;i++)
{
scanf("%d",&b[i]);
}
init();
manacher();
int ans = 0;
for(int i = 1;i <= l;i += 2)
{
for(int j = i + p[i] - 1;j - i > ans;j -= 2)
{
if(j - i + 1 <= p[j])
{
ans = max(ans,j - i);
break;
}
}
}
printf("Case #%d: ",++kase);
printf("%d\n",ans / 2 * 3);
}
return 0;
}