Hotaru's problem HDU - 5371(manacher)

半城伤御伤魂 提交于 2020-01-28 07:08:51

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:

  1. the first part is the same as the thrid part,
  2. 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;
}

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!