题解APIO2014回文串

Posted Twilight_Sx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解APIO2014回文串相关的知识,希望对你有一定的参考价值。

  哇哦~想不到我有生之年竟然能够做出字符串的题目ヾ(??▽?)ノ虽然这题比较裸但依然灰常开心!

  首先有一个棒棒的性质:本质不同的回文串最多有 O(n) 个。首先 manacher 把它们都找出来,然后问题就变成了给定 n 个子串,求它们在原串中出现的次数。求出 height 然后二分一下即可(这个好像是SA 的基础操作?)。

#include <bits/stdc++.h>
using namespace std;
#define maxn 601550
#define CNST 22
int n, N, m, p1[maxn], p2[maxn], rk[maxn], bits[CNST];
int p[maxn], rec[maxn], t[maxn], y[maxn], Log[maxn];
int num[maxn], SA[maxn], ST[maxn][CNST];
long long ans;
char a[maxn], s[maxn];

void pre()
{
    s[0] = s[1] = #; s[2 * n + 2] = ?;
    for(int i = 0; i < n; i ++) s[i * 2 + 2] = a[i], s[i * 2 + 3] = #;
    N = n * 2 + 2;
}

void Up(int &x, int y) { x = (x > y) ? x : y; }
void manacher()
{
    int mid = 0, mr = 0;
    for(int i = 0; i < N; i ++)
    {
        if(i <= mr) p[i] = min(p[(mid << 1) - i], p[mid] + mid - i);
        else p[i] = 1; Up(rec[i + p[i] - 1], p[i]);
        while(s[i + p[i]] == s[i - p[i]])
        {
            p[i] ++;
            Up(rec[i + p[i] - 1], p[i]);
        }
        if(p[i] + i - 1 > mr) mr = p[i] + i - 1, mid = i;
    }
}

//SA
void Rsort(int *p, int *x, int *id)
{
    for(int i = 1; i <= m; i ++) t[i] = 0; 
    for(int i = 1; i <= n; i ++) t[p[i]] ++;
    for(int i = 1; i <= m; i ++) t[i] += t[i - 1];
    for(int i = n; i >= 1; i --) x[t[p[id[i]]] --] = id[i];
}

bool cmp(int x, int y) { return y && (p1[x] == p1[y] && p2[x] == p2[y]); }  
void Get_SA()
{
    m = 128;
    for(int k = 0; bits[k] <= n; k ++)
    {
        for(int i = 1; i <= n; i ++)
            p1[i] = rk[i], p2[i] = (i + bits[k] <= n) ? rk[i + bits[k]] : 0;
        Rsort(p2, y, num); Rsort(p1, SA, y);
        for(int i = 1, p = 0; i <= n; m = p, i ++) 
            rk[SA[i]] = cmp(SA[i - 1], SA[i]) ? p : ++ p;
        if(m >= n) break;
    }
}

void Get_Height()
{
    for(int i = 1, k = 0; i <= n; i ++)
    {
        if(k) k --;
        int j = SA[rk[i] - 1];
        while(max(i, j) + k - 1 <= n && a[j + k - 1] == a[i + k - 1]) k ++;
        ST[rk[i]][0] = k;
    }
}

void Build()
{
    for(int j = 1; j < CNST; j ++)
        for(int i = 1; i + bits[j] - 1 <= n; i ++)
            ST[i][j] = min(ST[i][j - 1], ST[i + bits[j - 1]][j - 1]);
}

int RMQ(int x, int y)
{
    if(y < x) swap(x, y);
    int k = Log[y - x + 1];
    return min(ST[x][k], ST[y - bits[k] + 1][k]);
}

int Query(int x, int len)
{
    int l = 1, r = rk[x], ans2 = rk[x], ans1 = rk[x] + 1;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        if(RMQ(rk[x], mid) >= len) ans1 = mid, r = mid - 1;
        else l = mid + 1;
    }
    
    ans1 --; l = rk[x] + 1, r = n;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        if(RMQ(rk[x] + 1, mid) >= len) ans2 = mid, l = mid + 1;
        else r = mid - 1;
    }
    return ans2 - ans1 + 1;
}

void init()
{
    Log[0] = -1; for(int i = 1; i < maxn; i ++) Log[i] = Log[i >> 1] + 1;
    bits[0] = 1; for(int i = 1; i < CNST; i ++) bits[i] = bits[i - 1] << 1;
    for(int i = 1; i < maxn; i ++) num[i] = i; 
}

int main()
{
    init();
    scanf("%s", a); n = strlen(a);
    pre(); manacher();
    for(int i = 1; i <= n; i ++) rk[i] = a[i - 1];
    Get_SA(); Get_Height(); Build();
    for(int i = 1; i < N; i ++)
    {
        if(s[i] == #) continue; 
        int r = (i - 2) >> 1;
        int l = r - rec[i] + 1; r ++, l ++;
        int t = Query(l, r - l + 1);
        ans = max(ans, 1ll * t * (r - l + 1));
    }
    printf("%lld
", ans);
    return 0;
}

 

以上是关于题解APIO2014回文串的主要内容,如果未能解决你的问题,请参考以下文章

题解APIO2014回文串

BZOJ 3676 [Apio2014]回文串(回文树)

BZOJ3676 [Apio2014]回文串

BZOJ3676: [Apio2014]回文串

BZOJ 3676[Apio2014]回文串

P3649 [APIO2014]回文串(回文自动机)