[模板] manacher(教程)

还是不会马拉车啊.今天又学了一遍,在这里讲一下.

其实就是一个很妙的思路,就是设置一个辅助的数组len,记录每个点的最大对称长度,然后再存一个mx记录最大的对称子串的右端点.先开二倍数组,然后一点点扩大.有两种情况,一种i比mx大,这种只好暴力匹配了.还有一种就是i<mx,然后比较mx-i和len[2*po - i](po就是mx的对称中心),假如mx>i,那么说明无法再扩展,len[i] = len[2 * po - i];否则还需要暴力匹配.假如不好想,自己画个图就行了.

这里还有一个更负责的教程:

https://www.cnblogs.com/z360/p/6375514.html

大家可以对照看一看.

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(register int i = a;i <= n;i++)
#define lv(i,a,n) for(register int i = a;i >= n;i--)
#define clean(a) memset(a,0,sizeof(a))
const int INF = 1 << 30;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
        if(c == '-') op = 1;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
        x = x * 10 + c - '0';
    if(op) x = -x;
}
template <class T>
void write(T x)
{
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}
char s1[11000002];
char s[22000002];
int len[22000002];
int l = 0;
int po = 0;
int maxr = 0;
int main()
{
    scanf("%s",s1 + 1);
    l = strlen(s1 + 1);
    s[0] = '@';
    duke(i,1,2 * l + 1)
    {
        if(i % 2 == 1)
        s[i] = '*';
        else
        s[i] = s1[i / 2];
    }
    /*duke(i,0,2 * l + 1)
    printf("%c ",s[i]);
    puts("");*/
    int mx = -1,ans = 0,po = 0;
    duke(i,1,2 * l + 1)
    {
        if(mx > i)
        len[i] = min(mx - i,len[2 * po - i]);
        else
        len[i] = 1;
        while(s[i - len[i]] == s[i + len[i]])
        len[i]++;
        if(len[i] + i > mx)
        {
            mx = len[i] + i;
            po = i;
        }
        ans = max(ans,len[i] - 1);
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/DukeLv/p/9953588.html