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 }
代码君

 

posted @ 2015-04-20 16:58  AOQNRMGYXLMV  阅读(465)  评论(0编辑  收藏  举报