Manacher算法求回文半径

http://wenku.baidu.com/link?url=WFI8QEEfzxng9jGCmWHoKn0JBuHNfhZ-tKTDMux34CeY8UNUwLVPeY5HA3TyoKU2XegXFPifjunarW-YmXFrP_m8-3DEhBu1MHxHghHqD0O

这篇讲的比较好,准备一个模板,做题的时候用。

void manacher()
{
    int mx = 0, id = 0;
    for (int i = 1; i <= n; i++)
    {
        if (mx > i)
            p[i] = min(p[id * 2 - i], mx - i);
        else
            p[i] = 1;
        while (a[i + p[i]] == a[i - p[i]])
            p[i]++;
        if (mx < p[i] + i)
        {
            mx = p[i] + i;
            id = i;
        }
    }
}

这个初始化的时候是从1开始的

for (int i = 1; i <= n; i++)
{
            a[i * 2 - 1] = str[i]; 
            a[i * 2] = -1;
}

其中p表示回文半径,str是原串,a表示添加字符之后的串

两个例题:

hdu5340

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>

using namespace std;
typedef long long LL;
const int maxn = 20010;
char str[maxn], a[maxn<<1];
int p[maxn<<1], L[maxn<<1], R[maxn<<1];
int n;
void manacher()
{
    int mx = 0, id = 0;
    for (int i = 1; i <= n; i++)
    {
        if (mx > i)
            p[i] = min(p[id * 2 - i], mx - i);
        else
            p[i] = 1;
        while (a[i + p[i]] == a[i - p[i]])
            p[i]++;
        if (mx < p[i] + i)
        {
            mx = p[i] + i;
            id = i;
        }
    }
}
bool solve()
{
    for (int i = 1; i <= L[0]; i++)
    {
        for (int j = 1; j <= R[0]; j++)
        {
            int l = L[i] + 1;
            int r = R[j] - 1;
            if (r - l <= 0)
                continue;
            int mid = (l + r) / 2;
            if (p[mid] >= r - mid + 1)
                return true;
        }
    }
    return false;
}
int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        scanf("%s", str + 1);
        n = strlen(str + 1);
        for (int i = 1; i <= n; i++)
        {
            a[i * 2 - 1] = str[i]; 
            a[i * 2] = '#';
        }
        n = n * 2 - 1;
        a[0] = '$';
        a[n + 1] = '@';
        manacher();
        memset(L, 0, sizeof(L));
        memset(R, 0, sizeof(R));
        for (int i = 1; i <= n; i++)
        {
            int l = i - p[i] + 1;
            int r = i + p[i] - 1;
            if (l == 1)
                L[++L[0]] = r;
            if (r == n)
                R[++R[0]] = l;
        }
        if (solve())
            puts("Yes");
        else
            puts("No");
    }
    return 0;
}
View Code

hdu5371

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm> 
using namespace std;
typedef long long LL;
const int maxn = 100010;
int str[maxn], a[maxn<<1];
int p[maxn<<1];
int n;
void manacher()
{
    int mx = 0, id = 0;
    for (int i = 1; i <= n; i++)
    {
        if (mx > i)
            p[i] = min(p[id * 2 - i], mx - i);
        else
            p[i] = 1;
        while (a[i + p[i]] == a[i - p[i]])
            p[i]++;
        if (mx < p[i] + i)
        {
            mx = p[i] + i;
            id = i;
        }
    }
}
void print()
{
    for (int i = 1; i <= n; i++)
        printf("%d ", p[i]);
}
int main()
{
    int T;
    int kase = 0;
    scanf("%d", &T);
    while (T--)
    {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
            scanf("%d", &str[i]);
        for (int i = 1; i <= n; i++)
        {
            a[i * 2 - 1] = str[i]; 
            a[i * 2] = -1;
        }
        int m = n;
        n = n * 2 - 1;
        a[0] = -5;
        a[n + 1] = -8;
        manacher(); 
        int ans = 0;
        for (int i = 2; i <= n; i += 2)
            p[i] /= 2; 
        for (int i = 2; i <= n; i += 2)
        {
            if (p[i] * 3 < ans)
                continue;
            for (int j = p[i]; j * 3 >= ans; j--)
            {
                if (p[i + j * 2] >= j)
                {
                    ans = max(ans, j * 3);
                    break;
                }
            }
        }
        printf("Case #%d: %d\n", ++kase, ans);
    }
    return 0;
}
View Code

 

posted @ 2015-08-12 09:11  Howe_Young  阅读(493)  评论(0编辑  收藏  举报