zoukankan      html  css  js  c++  java
  • 后缀数组训练

    09国家集训队

    POJ 3261

    求允许重叠的至少出现k次的子串的最大长度

    二分答案,将高度数组分组,若某一组有k个数(或以上)满足高度大于k,则可行

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 const int maxn = 2e4 + 10;
     8 
     9 int n, t, k;
    10 int S[maxn];
    11 int rnk[maxn];
    12 int tmp[maxn];
    13 int sa[maxn];
    14 int lcp[maxn];
    15 
    16 bool compare_sa(int i, int j) {
    17     if (rnk[i] != rnk[j]) {
    18         return rnk[i] < rnk[j];
    19     } else {
    20         int ri = i + k <= n ? rnk[i + k] : -1;
    21         int rj = j + k <= n ? rnk[j + k] : -1;
    22         return ri < rj;
    23     }
    24 }
    25 
    26 void construct_sa(int* S, int *sa) {
    27     for (int i = 0; i <= n; i++) {
    28         sa[i] = i;
    29         rnk[i] = i < n ? S[i] : -1;
    30     }
    31     for (k = 1; k <= n; k *= 2) {
    32         sort(sa, sa + n + 1, compare_sa);
    33         tmp[sa[0]] = 0;
    34         for (int i = 1; i <= n; i++) {
    35             tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0);
    36         }
    37         for (int i = 0; i <= n; i++) {
    38             rnk[i] = tmp[i];
    39         }
    40     }
    41 }
    42 
    43 void construct_lcp(int *S, int *sa, int *lcp) {
    44     for (int i = 0; i <= n; i++) rnk[sa[i]] = i;
    45     int h = 0;
    46     lcp[0] = 0;
    47     for (int i = 0; i < n; i++) {
    48         int j = sa[rnk[i] - 1];
    49         if (h > 0) h--;
    50         for (; j + h < n && i + h < n; h++) {
    51             if (S[i + h] != S[j + h]) break;
    52         }
    53         lcp[rnk[i] - 1] = h;
    54     }
    55 }
    56 
    57 bool ck(int m) {
    58     int cnt = 1;
    59     for (int i = 1; i < n; i++) {
    60         if (lcp[i] >= m) {
    61             cnt++;
    62         } else {
    63             cnt = 1;
    64         }
    65         if (cnt >= t) {
    66             return true;
    67         }
    68     }
    69     return false;
    70 }
    71 
    72 int main() {
    73     scanf("%d%d", &n, &t);
    74     for (int i = 0; i < n; i++) {
    75         scanf("%d", &S[i]);
    76     }
    77     construct_sa(S, sa);
    78     construct_lcp(S, sa, lcp);
    79     int dn = 1, up = n + 1;
    80     while (up - dn > 1) {
    81         int mid = (dn + up) / 2;
    82         if (ck(mid)) {
    83             dn = mid;
    84         } else {
    85             up = mid;
    86         }
    87     }
    88     printf("%d
    ", dn);
    89     return 0;
    90 }
    View Code

     SPOJ694

    求一个串的所有不同子串数目

    总的子串数目减去重复数(利用高度数组读得)

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    int T;
    int k;
    int n;
    const int maxn = 1e3 + 10;
    int rnk[maxn], sa[maxn], tmp[maxn], lcp[maxn];
    
    string S;
    
    bool compare_sa(int i, int j) {
        if (rnk[i] != rnk[j]) {
            return rnk[i] < rnk[j];
        } else {
            int ri = i + k <= n ? rnk[i + k] : -1;
            int rj = j + k <= n ? rnk[j + k] : -1;
            return ri < rj;
        }
    }
    
    void construct_sa(string S, int *sa) {
        n = S.length();
        for (int i = 0; i <= n; i++) {
            sa[i] = i;
            rnk[i] = i < n ? S[i] : -1;
        }
    
        for (k = 1; k <= n; k *= 2) {
            sort(sa, sa + n + 1, compare_sa);
            tmp[sa[0]] = 0;
            for (int i = 1; i <= n; i++) {
                tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0);
            }
            for (int i = 0; i <= n; i++) {
                rnk[i] = tmp[i];
            }
        }
    }
    
    
    void construct_lcp(string S, int* sa, int* lcp) {
        for (int i = 0; i <= n; i++) rnk[sa[i]] = i;
    
        int h = 0;
        lcp[0] = 0;
        for (int i = 0; i < n; i++) {
            int j = sa[rnk[i] - 1];
            if (h > 0) h--;
            for (; i + h < n && j + h < n; h++) {
                if (S[i + h] != S[j + h]) break;
            }
            lcp[rnk[i] - 1] = h;
        }
    }
    
    int main() {
        cin >> T;
        while (T--) {
            cin >> S;
            construct_sa(S, sa);
            construct_lcp(S, sa, lcp);
            int ans = 0;
            for (int i = 1; i <= n; i++) {
                ans += n - sa[i] - lcp[i - 1];//i-1
            }
            printf("%d
    ", ans);
        }
    
    
        return 0;
    }
    View Code

    HDU - 4552

    求一个字符串的所有前缀在字符串中出现次数的总合

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long LL;
    const int maxn = 1e5 + 10;
    
    int n, k;
    int tmp[maxn], rnk[maxn], sa[maxn], lcp[maxn];
    char S[maxn];
    
    bool compare_sa(int i, int j) {
        if (rnk[i] != rnk[j]) {
            return rnk[i] < rnk[j];
        } else {
            int ri = i + k <= n ? rnk[i + k] : -1;
            int rj = j + k <= n ? rnk[j + k] : -1;
            return ri < rj;
        }
    }
    
    void construct_sa(int *sa) {
        for (int i = 0; i <= n; i++) {
            sa[i] = i;
            rnk[i] = i < n ? S[i] : -1;
        }
        for (k = 1; k <= n; k *= 2) {
            sort(sa, sa + n + 1, compare_sa);
            tmp[sa[0]] = 0;
            for (int i = 1; i <= n; i++) {
                tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0);
            }
            for (int i = 0; i <= n; i++) {
                rnk[i] = tmp[i];
            }
        }
    }
    
    void construct_lcp(int* sa, int* lcp) {
        for (int i = 0; i <= n; i++) rnk[sa[i]] = i;
        int h = 0;
        for (int i = 0; i <= n; i++) {
            int j = sa[rnk[i] - 1];
            if (h > 0) h--;
            for (; j + h < n && i + h < n; h++) {
                if (S[i + h] != S[j + h]) break;
            }
            lcp[rnk[i] - 1] = h;
        }
    }
    
    int main() {
        while (~scanf("%s", S)) {
            n = strlen(S);
            construct_sa(sa);
            construct_lcp(sa, lcp);
            LL ans = n;
            int t = rnk[0];
            int match = n;
            while (t < n) {
                match = min(match, lcp[t]);
                ans += match;
                t++;
            }
            t = rnk[0];
            match = n;
            while (t) {
                match = min(match, lcp[t - 1]);
                ans += match;
                t--;
            }
            printf("%lld
    ", ans % 256);
        }
    
        return 0;
    }
    跑得很慢 找机会再写
  • 相关阅读:
    7月15日考试 题解(链表+状压DP+思维题)
    暑假集训日记
    C# .NET 使用 NPOI 生成 .xlsx 格式 Excel
    JavaSE 基础 第42节 局部内部类
    JavaSE 基础 第41节 匿名内部类
    JavaSE 基础 第40节 内部类概述
    JavaSE 基础 第39节 接口的应用
    JavaSE 基础 第38节 接口的实现
    JavaSE 基础 第37节 接口概述
    JavaSE 基础 第36节 抽象类概述与使用
  • 原文地址:https://www.cnblogs.com/xFANx/p/8534917.html
Copyright © 2011-2022 走看看