hdu 4513 吉哥系列故事——完美队形II(拓展KMP算法)

采用在数字之间插入不可能数据(-1)

如:1 2 1

变为:-1  1   -1   2   -1   1   -1

利用性质:p[i] >= min(rem.right - i, odd[rem.left + (rem.right - i)])



我的理解:假设在前面某点mid,确定一个回文区间[rem[mid].left, rem[mid].right];而当以i(rem[mid].right > i > mid)为中点,

求它往两边发散的回文半径,可以利用i关于mid对称的点rem[mid].left + rem[mid].right - i已经算出的回文半径,再想两边发散,

不过也得受rem[mid].right - i限制,也就是

#include 
#include 
#include 
#define MAXN 100005
int a[MAXN * 2];
struct Rem{
    int left;
    int right;
}rem;
int odd[2 * MAXN];




int min(int a, int b)
{
    return (a < b) ? a : b;
}
int fun(int i, int m, int N)
{
    int l = i - m - 1, r = i + m + 1;
    int ret = 0;


    for(;(l > 0)&&(r <= N);--l, ++r)
    {
        if((a[r] == -1) ||  ((a[l] == a[r]) && ((r - l == 2)||(a[r] <= a[r - 2])  )))
            ++ret;
        else break;
    }
    return ret;
}


int main()
{
    int T, N;
    for(scanf("%d", &T); T--; )
    {
        scanf("%d", &N);
        int i = 0;
        a[++i] = -1;
        while(N--)
        {
            scanf("%d", &a[++i]);
            a[++i] = -1;
        }
        N = i;


        rem.left = rem.right = 0;
        int ans = 1;
        memset(odd, 0, sizeof(odd));
        for(int i = 1; i <= N; ++i)
        {
            int m = 0;
            if(rem.right > i)
                m = min(rem.right - i, odd[rem.left + (rem.right - i)]);//利用对称左右对称性质优化
            odd[i] = m + fun(i, m, N);


            if(i + odd[i] > rem.right)//当有最大右边覆盖,记录下来
            {
                rem.left = i - odd[i];
                rem.right = i + odd[i];
            }
            if(odd[i] > ans)
                ans = odd[i];
        }
        printf("%d\n", ans);
    }


    return 0;
}


你可能感兴趣的:(字符串处理)