POJ 2774 Long Long Message 后缀数组模板题

  题意

      给定字符串A、B,求其最长公共子串

  后缀数组模板题,求出height数组,判断sa[i]与sa[i-1]是否分属字符串A、B,统计答案即可。

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

using namespace std;

const int maxn = 200005;
char str[maxn];
int num[maxn];
int wa[maxn], wb[maxn], wv[maxn], sum[maxn];
int rank[maxn], sa[maxn], height[maxn];

bool cmp(int *r, int a, int b, int l)
{
    return (r[a] == r[b]) && (r[a+l] == r[b+l]);
}

void da(int *r, int *sa, int n, int m)
{
    int *x = wa, *y = wb, *t;
    for (int i = 1; i <= m; ++i)
        sum[i] = 0;
    for (int i = 1; i <= n; ++i)
        sum[x[i]=r[i]] ++;
    for (int i = 2; i <= m; ++i)
        sum[i] += sum[i-1];
    for (int i = n; i >= 1; --i)
        sa[sum[x[i]]--] = i;
    for (int i, j = 1, p = 1; p < n; j *= 2, m = p)
    {
        for (p = 0, i = n-j+1; i <= n; ++i)
            y[++p] = i;
        for (i = 1; i <= n; ++i)
            if (sa[i]-j >= 1)
                y[++p] = sa[i]-j;
        for (i = 1; i <= n; ++i)
            wv[i] = x[y[i]];
        for (i = 1; i <= m; ++i)
            sum[i] = 0;
        for (i = 1; i <= n; ++i)
            sum[wv[i]] ++;
        for (i = 2; i <= m; ++i)
            sum[i] += sum[i-1];
        for (i = n; i >= 1; --i)
            sa[sum[wv[i]]--] = y[i];
        for (t = x, x = y, y = t, p = 1, x[sa[1]] = 1, i = 2; i <= n; ++i)
            x[sa[i]] = cmp(y, sa[i], sa[i-1], j) ? p : ++p;
    }/*
    for (int i = 1; i <= n; ++i)
        printf("%d ", sa[i]);
    printf("\n");*/
}

void calheight(int *r, int *sa, int n)
{
    for (int i = 1; i <= n; ++i)
        rank[sa[i]] = i;/*
    for (int i = 1; i <= n; ++i)
        printf("%d ", rank[i]);
    printf("\n");*/
    int k = 0;
    for (int i = 1; i <= n; ++i)
    {
        if (k > 0)
            k --;
        int j = sa[rank[i]-1];
        while (r[i+k] == r[j+k] && i+k <= n && j+k <= n)
            k ++;
        height[rank[i]] = k;
    }
}

int main()
{
    scanf("%s", str);
    int l1 = strlen(str);
    for (int i = 1; i <= l1; ++i)
        num[i] = str[i-1]-'a'+2;
    num[l1+1] = 1;
    scanf("%s", str);
    int l2 = strlen(str);
    for (int i = 1; i <= l2; ++i)
        num[l1+1+i] = str[i-1]-'a'+2;
    da(num, sa, l1+l2+1, 30);
    calheight(num, sa, l1+l2+1);
    int ans = 0;
    for (int i = 3; i <= l1+l2+1; ++i)
        if ((sa[i] <= l1 && sa[i-1] >= l1+2)
         || (sa[i-1] <= l1 && sa[i] >= l1+2))
            ans = max(ans, height[i]);
    printf("%d\n", ans);
    return 0;
}

 

posted @ 2017-02-17 19:25  Splay  阅读(313)  评论(0编辑  收藏  举报