• POJ3415--Common Substrings 后缀数组 +单调栈


    题意: 求长度大于等于K的公共子串的个数。位置不同就算不同。

    后缀数组求依次SA LCP, 然后就是统计答案了, 暴力统计n^2复杂度显然不可以, 我们可以利用lcp数组的"部分单调性", 用一个栈,栈中保存小于等于当前lcp的原数组的下标, 

    两次统计, 第一次统计, 按B串统计, 把A串大于等于K的那一部分的长度加起来保存在tot中, 出栈时则需要从tot中减去多余的哪一步分,同时记录个数, 这样遇到一次B串 求一次ans

    然后反过来 按A串 统计,这一步和上一步相同。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    const int MAXN = 2e5+10;
    char str[MAXN];
    int step, rank[MAXN], tmp[MAXN], sa[MAXN],lcp[MAXN];
    int len;
    bool cmp(int i, int j) {
        if (rank[i] != rank[j]) {
            return rank[i] < rank[j];
        }
        int ri = i + step <= len ? rank[i+step] : -1;
        int rj = j + step <= len ? rank[j+step] : -1;
        return ri < rj;
    }
    void build_sa() {
        for (int i = 0; i <= len; i++) {
            sa[i] = i;
            rank[i] = i < len ? str[i] : -1;
        }
        for (step = 1; step <= len; step <<= 1) {
            std::sort (sa, sa+len+1, cmp);
            tmp[sa[0]] = 0;
            for (int i = 1; i <= len; i++) {
                tmp[sa[i]] = tmp[sa[i-1]] + (cmp(sa[i-1], sa[i]) ? 1 : 0);
            }
            for (int i = 0; i <= len; i++) {
                rank[i] = tmp[i];
            }
        }
    }
    void build_lcp() {
        for (int i = 0; i <= len; i++) {
            rank[sa[i]] = i;
        }
        int h = 0;
        lcp[0] = 0;
        for (int i = 0; i <= len; i++) {
            int j = sa[rank[i]-1];
            if (h > 0) {
                h--;
            }
            while (j+h < len && i + h < len && str[i+h] == str[j+h]) {
                h++;
            }
            lcp[rank[i]] = h;
        }
    }
    typedef long long LL;
    LL ans;
    int K, pt1, pt2, stack1[MAXN],stack2[MAXN], top;
    void solve () {
        ans = 0;
        top = -1;
        LL tot = 0;
        for (int i = 0; i <= len; i++) {
            if (lcp[i] < K) {
                top = -1;
                tot = 0;
            } else {
                int cnt = 0;
                if (sa[i-1] < pt2) {
                    tot += lcp[i] - K + 1;
                    cnt++;
                }
                while (~top && lcp[stack1[top]] >= lcp[i]) {
                    tot -= stack2[top] * (lcp[stack1[top]] - lcp[i]);
                    cnt += stack2[top];
                    top--;
                }
                stack1[++top] = i;
                stack2[top] = cnt;
                if (sa[i] >= pt2) {
                    ans += tot;
                }
            }
        }
        top = -1;
        tot = 0;
        for (int i = 0; i <= len; i++) {
            if (lcp[i] < K) {
                top = -1;
                tot = 0;
            } else {
                int cnt = 0;
                if (sa[i-1] >= pt2) {
                    tot += lcp[i] - K + 1;
                    cnt++;
                }
                while (~top && lcp[stack1[top]] >= lcp[i]) {
                    tot -= stack2[top] * (lcp[stack1[top]] - lcp[i]);
                    cnt += stack2[top];
                    top--;
                }
                stack1[++top] = i;
                stack2[top] = cnt;
                if (sa[i] < pt2) {
                    ans += tot;
                }
            }
        }
        printf("%lld
    ", ans);
    }
    int main() {
        while (scanf ("%d", &K), K) {
            int len1;
            scanf ("%s", str);
            len1 = strlen(str);
            str[len1] = '#';
            scanf ("%s", str+len1+1);
            pt2 = len1 + 1;
            len = strlen(str);
            build_sa();
            build_lcp();
            solve();
        }
        return 0;
    }
  • 相关阅读:
    September 17th 2016 Week 38th Saturday
    【2016-09-16】UbuntuServer14.04或更高版本安装问题记录
    September 16th 2016 Week 38th Friday
    September 11th 2016 Week 38th Sunday
    September 12th 2016 Week 38th Monday
    September 10th 2016 Week 37th Saturday
    September 9th 2016 Week 37th Friday
    c++暂停
    八皇后问题
    ( 转转)Android初级开发第九讲--Intent最全用法(打开文件跳转页面等)
  • 原文地址:https://www.cnblogs.com/oneshot/p/4711699.html
Copyright © 2020-2023  润新知