SPOJ DISUBSTR(后缀数组)

 

传送门:DISUBSTR

题意:给定一个字符串,求不相同的子串。

分析:对于每个sa[i]贡献n-a[i]个后缀,然后减去a[i]与a[i-1]的公共前缀height[i],则每个a[i]贡献n-sa[i]-height[i]个不同子串。

#include <iostream>

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <queue>

using namespace std;

const int maxn = 1010;



int sa[maxn]; 

int t1[maxn], t2[maxn], c[maxn];

int rank[maxn], height[maxn];

int s[maxn];

char str[maxn];



void build_sa(int s[], int n, int m) {

    int i, j, p, *x = t1, *y = t2;

    for (i = 0; i < m; i++) c[i] = 0;

    for (i = 0; i < n; i++) c[x[i] = s[i]]++;

    for (i = 1; i < m; i++) c[i] += c[i-1];

    for (i = n-1; i >= 0; i--) sa[--c[x[i]]] = i;



    for (j = 1; j <= n; j <<= 1) {

        p = 0;

        for (i = n-j; i < n; i++) y[p++] = i;

        for (i = 0; i < n; i++) 

            if (sa[i] >= j) 

                y[p++] = sa[i] - j;

        for (i = 0; i < m; i++) c[i] = 0;

        for (i = 0; i < n; i++) c[x[y[i]]]++;

        for (i = 1; i < m; i++) c[i] += c[i-1];

        for (i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];



        swap(x, y);

        p = 1, x[sa[0]] = 0;

        for (i = 1; i < n; i++) 

            x[sa[i]] = y[sa[i-1]] == y[sa[i]] && y[sa[i-1]+j] == y[sa[i]+j] ? p-1 : p++;



        if (p >= n) break;

        m = p;

    }

}



void getHeight(int s[],int n) {

    int i, j, k = 0;

    for (i = 0; i <= n; i++)

        rank[sa[i]] = i;

    for (i = 0; i < n; i++) {

        if (k) k--;

        j = sa[rank[i]-1];

        while (s[i+k] == s[j+k]) k++;

        height[rank[i]]=k;

    }

}

int main() {

    int T;

    scanf("%d", &T);

    while (T--) {

        scanf("%s", str);

        int n = strlen(str);

        for (int i = 0; i <= n; i++)

            s[i] = str[i];

        build_sa(s, n+1, 128);

        getHeight(s, n);

        int ans = 0;

        for (int i = 1; i <= n; i++)

            ans += n - sa[i] - height[i];

        printf("%d\n", ans);

    }

    return 0;

}
View Code

 

你可能感兴趣的:(substr)