zoukankan      html  css  js  c++  java
  • UVa 11107 (后缀数组 二分) Life Forms

    利用height值对后缀进行分组的方法很常用,好吧,那就先记下了。

    题意:

    给出n个字符串,求一个长度最大的字符串使得它在超过一半的字符串中出现。

    多解的话,按字典序输出全部解。

    分析:

    在所有输入的字符串后面加一个原串中没有的且互不相同的字符,然后将新得到的n个字符串拼接成一个长的字符串。(为什么要加互不相同的分割字符,这里始终想不明白)

    首先二分最大公共字串的长度p。扫描一遍height数组,每遇到一个height[i] < p便开辟一个新段,这样就将height数组拆分为若干段。而且每一段的所有字符都有一个长度为p的公共前缀。只要某一段中包含了超过 n / 2 的原串的后缀,就满足条件了。

    如何判断是否包含了某个原串的后缀,用一个flag标记数组即可实现。

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 using namespace std;
      5 
      6 const int maxn = 1001 * 100 + 10;
      7 
      8 struct SuffixArray
      9 {
     10     int s[maxn];
     11     int sa[maxn];
     12     int rank[maxn];
     13     int height[maxn];
     14     int t[maxn], t2[maxn], c[maxn];
     15     int n;
     16 
     17     void clear() { n = 0; memset(sa, 0, sizeof(sa)); }
     18 
     19     void build_sa(int m)
     20     {
     21         int i, *x = t, *y = t2;
     22         for(i = 0; i < m; i++) c[i] = 0;
     23         for(i = 0; i < n; i++) c[x[i] = s[i]]++;
     24         for(i = 1; i < m; i++) c[i] += c[i - 1];
     25         for(i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;
     26         for(int k = 1; k <= n; k <<= 1)
     27         {
     28             int p = 0;
     29             for(i = n - k; i < n; i++) y[p++] = i;
     30             for(i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i] - k;
     31             for(i = 0; i < m; i++) c[i] = 0;
     32             for(i = 0; i < n; i++) c[x[y[i]]]++;
     33             for(i = 1; i < m; i++) c[i] += c[i - 1];
     34             for(i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
     35             swap(x, y);
     36             p = 1; x[sa[0]] = 0;
     37             for(i = 1; i < n; i++)
     38                 x[sa[i]] = y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k] ? p - 1 : p++;
     39             if(p >= n) break;
     40             m = p;
     41         }
     42     }
     43 
     44     void build_height()
     45     {
     46         int i, j, k = 0;
     47         for(i = 0; i < n; i++) rank[sa[i]] = i;
     48         for(i = 0; i < n; i++)
     49         {
     50             if(k) k--;
     51             j = sa[rank[i] - 1];
     52             while(s[i + k] == s[j + k]) k++;
     53             height[rank[i]] = k;
     54         }
     55     }
     56 };
     57 
     58 const int maxc = 100 + 10;
     59 const int maxl = 1000 + 10;
     60 SuffixArray sa;
     61 int n;
     62 char word[maxl];
     63 int idx[maxn];
     64 bool flag[maxc];
     65 
     66 void print_sub(int L, int R)
     67 {
     68     for(int i = L; i < R; i++) printf("%c", sa.s[i] - 1 + 'a');
     69     puts("");
     70 }
     71 
     72 bool good(int L, int R)
     73 {
     74     memset(flag, false, sizeof(flag));
     75     int cnt = 0;
     76     for(int i = L; i < R; i++)
     77     {
     78         int x = idx[sa.sa[i]];
     79         if(x != n && !flag[x]) { flag[x]  = true; cnt++; }
     80     }
     81     return cnt > n / 2;
     82 }
     83 
     84 bool print_solution(int len, bool print)
     85 {
     86     int L = 0;
     87     for(int R = 1; R <= sa.n; R++)
     88     {
     89         if(R == sa.n || sa.height[R] < len)
     90         {
     91             if(good(L, R))
     92             {
     93                 if(print) print_sub(sa.sa[L], sa.sa[L] + len);
     94                 else return true;
     95             }
     96             L = R;
     97         }
     98     }
     99     return false;
    100 }
    101 
    102 void solve(int maxlen)
    103 {
    104     if(!print_solution(1, false)) puts("?");
    105     else
    106     {
    107         int L = 1, R = maxlen, M;
    108         while(L < R)
    109         {
    110             M = L + (R - L + 1) / 2;
    111             if(print_solution(M, false)) L = M;
    112             else R = M - 1;
    113         }
    114         print_solution(L, true);
    115     }
    116 }
    117 
    118 void add(int ch, int i)
    119 {
    120     idx[sa.n] = i;
    121     sa.s[sa.n++] = ch;
    122 }
    123 
    124 int main()
    125 {
    126     //freopen("in.txt", "r", stdin);
    127 
    128     int kase = 0;
    129     while(scanf("%d", &n) == 1 && n)
    130     {
    131         if(kase++ > 0) puts("");
    132         sa.clear();
    133         int maxlen = 0;
    134         for(int i = 0; i < n; i++)
    135         {
    136             scanf("%s", word);
    137             int sz = strlen(word);
    138             maxlen = max(maxlen, sz);
    139             for(int j = 0; j < sz; j++) add(word[j] - 'a' + 1, i);
    140             add(i + 100, n);
    141         }
    142         add(0, n);
    143 
    144         sa.build_sa(100 + n);
    145         sa.build_height();
    146         solve(maxlen);
    147     }
    148 
    149     return 0;
    150 }
    代码君
  • 相关阅读:
    CF1187E Tree Painting
    [TJOI2017]城市
    [HNOI2010]合唱队
    2020暑假多校补题记录
    树形dp总结
    2017CCPC 秦皇岛 G. Numbers (贪心 + java大数)
    LOJ 2491 求和 (LCA + 前缀和)
    LOJ 10105. 欧拉回路
    Luogu P3953 逛公园 (最短路+dp)
    LOJ#2718. 「NOI2018」归程 (kruskal重构树)
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4442030.html
Copyright © 2011-2022 走看看