• SPOJ 694 && SPOJ 705 (不重复子串个数:后缀数组)


    题意

    给定一个字符串,求它的所有不重复子串的个数

    思路

    一个字符串的子串都必然是它的某个后缀的前缀。对于每一个sa[i]后缀,它的起始位置sa[i],那么它最多能得到该后缀长度个子串(n-sa[i]个),而其中有height[i]个是与前一个后缀相同的,所以它能产生的实际后缀个数便是n-sa[i]-height[i]。遍历一次所有的后缀,将它产生的后缀数加起来便是答案。

    代码

      [cpp] #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <string> #include <cstring> #include <vector> #define MID(x,y) ((x+y)/2) #define MEM(a,b) memset(a,b,sizeof(a)) using namespace std; //Suffix Array const int maxn = 1005; int wx[maxn], wy[maxn], wxy[maxn], hs[maxn]; int r[maxn], sa[maxn], ranks[maxn], height[maxn]; int cmp(int r[], int a, int b, int l){ return (r[a] == r[b] && r[a+l] == r[b+l]); } //r is the string, and r[n-1] = 0, this means we should add a '0' at the end of the string. void da(int r[], int sa[], int ranks[], int height[], int n, int m){ //calculate sa[], begin at 1 because sa[0] = "0". int i, j, len, p, k = 0, *x = wx, *y = wy, *t; for (i = 0; i < m; i ++) hs[i] = 0; for (i = 0; i < n; i ++) hs[x[i] = r[i]] ++; for (i = 1; i < m; i ++) hs[i] += hs[i-1]; for (i = n-1; i >= 0; i --) sa[-- hs[x[i]]] = i; for (len = 1, p = 1; p < n; len *= 2, m = p){ for (p = 0, i = n - len; i < n; i ++) y[p ++] = i; for (i = 0; i < n; i ++) if (sa[i] >= len) y[p ++] = sa[i] - len; for (i = 0; i < n; i ++) wxy[i] = x[y[i]]; for (i = 0; i < m; i ++) hs[i] = 0; for (i = 0; i < n; i ++) hs[wxy[i]] ++; for (i = 1; i < m; i ++) hs[i] += hs[i-1]; for (i = n-1; i >= 0; i --) sa[-- hs[wxy[i]]] = y[i]; for (t = x, x = y, y = t, p = 1, i = 1, x[sa[0]] = 0; i < n; i ++) x[sa[i]] = cmp(y, sa[i-1], sa[i], len)?p-1:p ++; } //calculate height[], height[n-1] is null because we add a '0' at the end of the string. for (i = 1; i < n; i ++) ranks[sa[i]] = i; for (i = 0; i < n - 1; height[ranks[i++]] = k) for (k?k--:0, j = sa[ranks[i]-1]; r[i+k] == r[j+k]; k ++); } int main(){ //freopen("test.in", "r", stdin); //freopen("test.out", "w", stdout); int t; scanf("%d", &t); while(t --){ char tmps[1005] = {0}; scanf("%s", tmps); MEM(r, 0); int n = strlen(tmps); for (int i = 0; i < n; i ++) r[i] = tmps[i]; da(r, sa, ranks, height, n + 1, 100); int res = 0; for (int i = 1; i <= n; i ++){ res += n - sa[i] - height[i]; } printf("%d ", res); } return 0; } [/cpp]
  • 相关阅读:
    测试需要做单元测试吗?
    测试流程如何落地?
    你真的需要自动化测试吗?
    aformmodel的简单例子
    面试突击58:truncate、delete和drop的6大区别
    面试突击57:聚簇索引=主键索引吗?
    面试突击56:聚簇索引和非聚簇索引有什么区别?
    33岁程序员的年中总结
    面试突击59:一个表中可以有多个自增列吗?
    java list遍历添加元素_【转】:java遍历List时动态添加和删除元素
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/4114336.html
Copyright © 2020-2023  润新知