后缀数组 (板子)

存一个板子… 好难呀
题目是求一个字符串有多少中不同的字串.

char s[maxn];
int sa[maxn], t[maxn], t2[maxn], tt[maxn], c[maxn], ss[maxn];
int Rank[maxn], height[maxn];

bool cmp(int *r, int a, int b, int l) {
    return r[a] == r[b] && r[a+l] == r[b+l];
}
// 名次数组:名次数组 Rank[i]保存的是 Suffix(i)在所有后缀中从小到大排列的“名次”。
/*后缀数组:后缀数组 SA 是一个一维数组,它保存 1..n 的某个排列 SA[1],
SA[2],......,SA[n],并且保证 Suffix(SA[i]) < Suffix(SA[i+1]),1≤i<n。
也就是将 S 的 n 个后缀从小到大进行排序之后把排好序的后缀的开头位置顺
次放入 SA 中。*/
//SA数组最后1-len代表的是所有的下标、SA[0]是添加的末尾
//height是1-len代表 定义 height[i]=suffix(sa[i-1])和 suffix(sa[i])的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀。
//一定要记住下标为0 的是添加的0,height和SA都是
void build_sa(int *r, int n, int m) {
    int *x = t, *y = t2;
    for (int i = 0; i < m; i++) c[i] = 0;
    for (int i = 0; i < n; i++) c[x[i] = r[i]]++;
    for (int i = 1; i < m; i++) c[i] += c[i-1];
    for (int i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;
    for (int j = 1; ; j <<= 1) {
        int p = 0;
        for (int i = n - j; i < n; i++) y[p++] = i;
        for (int i = 0; i < n; i++) if (sa[i] >= j) y[p++] = sa[i] - j;
        for (int i = 0; i < n; i++) tt[i] = x[y[i]];
        for (int i = 0; i < m; i++) c[i] = 0;
        for (int i = 0; i < n; i++) c[tt[i]]++;
        for (int i = 1; i < m; i++) c[i] += c[i-1];
        for (int i = n - 1; i >= 0; i--) sa[--c[tt[i]]] = y[i];
        swap(x, y), p = 1, x[sa[0]] = 0;
        for (int i = 1; i < n; i++)
            x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1 : p++;
        if (p >= n) break;
        m = p;
    }
}

void getHeight(int *r, int n) {
    int k = 0;
    for (int i = 1; i <= n; i++) Rank[sa[i]] = i;
    for (int i = 0; i < n; i++) {
        if (k) k--;
        int j = sa[Rank[i] - 1];
        while (r[i+k] == r[j+k]) k++;
        height[Rank[i]] = k;
    }
}

void solve() {
    scanf("%s", s);
    int len = strlen(s);
    for (int i = 0; i < len; i++)
        ss[i] = s[i];
    ss[len] = 0; //使用ss代替s,并且在最后添加一个0构成  s + '0'
    build_sa(ss, len+1, 256);
    getHeight(ss, len);
    ll ans = 0;
    for (int i = 1 ; i <= len ; i ++) {
        ans += len - sa[i] - height[i];
    }
    cout << ans << endl;
}

猜你喜欢

转载自blog.csdn.net/Anxdada/article/details/81279147