POJ 3415 Common Substrings 后缀数组

来源:互联网 发布:氮泵 副作用 知乎 编辑:程序博客网 时间:2024/06/05 09:29

题目:

http://poj.org/problem?id=3415

题意:

给定两个字符串,求这两个字符串中长度大于等于k的公共子串的数量

思路:

不得不说,这题我不会,看的别人的,心累。。。看这篇http://www.cnblogs.com/luxiaoming/p/5270984.html

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long ll;const int N = 200000 + 10, INF = 0x3f3f3f3f;int sa[N], height[N], rnk[N], wa[N], wb[N], c[N];char str[N];int s[N];int stk[N][2];bool cmp(int *r, int a, int b, int l){    return r[a] == r[b] && r[a+l] == r[b+l];}void Rsort(int *x, int *y, int n, int m){    for(int i = 0; i < m; i++) c[i] = 0;    for(int i = 0; i < n; i++) c[x[y[i]]]++;    for(int i = 1; i < m; i++) c[i] += c[i-1];    for(int i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];}void da(int *s, int n, int m){    int *x = wa, *y = wb;    for(int i = 0; i < n; i++) x[i] = s[i], y[i] = i;    Rsort(x, y, n, m);    for(int j = 1, p = 1; p < n; j *= 2, m = p)    {        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;        Rsort(x, y, n, m);        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++;    }}void get_height(int *s, int n){    int i, j, k = 0;    for(i = 0; i <= n; i++) rnk[sa[i]] = i;    for(i = 0; i < n; height[rnk[i++]] = k)        for(k ? --k : 0, j = sa[rnk[i]-1]; s[i+k] == s[j+k]; k++);}int main(){    int k;    while(scanf("%d", &k), k)    {        scanf("%s", str);        int len = 0, len_1 = strlen(str);        for(int i = 0; str[i]; i++) s[len++] = str[i];        s[len++] = '$';        scanf("%s", str);        for(int i = 0; str[i]; i++) s[len++] = str[i];        s[len] = 0;        da(s, len+1, 150);        get_height(s, len);        ll ans = 0, num = 0;        int top = 0;        for(int i = 2; i <= len; i++)        {            if(height[i] < k) top = 0, num = 0;            else            {                int tmp = 0;                if(sa[i-1] < len_1) tmp++, num += height[i] - k + 1;                while(top > 0 && height[i] <= stk[top-1][0])                {                    top--;                    num -= stk[top][1] * (stk[top][0] - height[i]);                    tmp += stk[top][1];                }                stk[top][0] = height[i], stk[top++][1] = tmp;                if(sa[i] > len_1) ans += num;            }        }        top = 0, num = 0;        for(int i = 2; i <= len; i++)        {            if(height[i] < k) top = 0, num = 0;            else            {                int tmp = 0;                if(sa[i-1] > len_1) tmp++, num += height[i] - k + 1;                while(top > 0 && height[i] <= stk[top-1][0])                {                    top--;                    num -= stk[top][1] * (stk[top][0] - height[i]);                    tmp += stk[top][1];                }                stk[top][0] = height[i], stk[top++][1] = tmp;                if(sa[i] < len_1) ans += num;            }        }//        for(int i = 0; i < len_1; i++)//            for(int j = len_1 + 1; j < len; j++)//            {//                int st = min(rnk[i], rnk[j]), en = max(rnk[i], rnk[j]);//                int t = INF;//                for(int q = st+1; q <= en; q++) t = min(t, height[q]);//这步可以优化掉,不过无所谓啦。。。//                if(t >= k)ans += t - k + 1;//            }        printf("%lld\n", ans);    }    return 0;}
阅读全文
0 0
原创粉丝点击