poj 3294 Life Forms - 后缀数组 - 二分答案

题目传送门

  传送门I

  传送门II

题目大意

  给定$n$个串,询问所有出现在严格大于$\frac{n}{2}$个串的最长串。不存在输出'?'

  用奇怪的字符把它们连接起来。然后求sa,hei,二分答案,按mid分组。

  判断每一组存在的后缀属于的原串的种类数是不是存在那么多个。

  这个做法可以推广到多串求LCS,然后多个log,完美在SPOJ上T掉。

Code

  1 /**
  2  * poj
  3  * Problem#3294
  4  * Accepted
  5  * Time: 391ms
  6  * Memory: 5024k
  7  */
  8 #include <iostream>
  9 #include <cstring>
 10 #include <cstdlib>
 11 #include <cstdio>
 12 #ifndef WIN32
 13 #define Auto "%lld"
 14 #else
 15 #define Auto "%I64d"
 16 #endif
 17 using namespace std;
 18 typedef bool boolean;
 19 #define ll long long
 20 
 21 #define pii pair<int, int>
 22 #define fi first
 23 #define sc second
 24 
 25 const int N = 1e5 + 105, M = 105;
 26 
 27 typedef class Pair3 {
 28     public:
 29         int x, y, id;
 30 
 31         Pair3() {    }
 32         Pair3(int x, int y, int id):x(x), y(y), id(id) {    }
 33 }Pair3;
 34 
 35 typedef class SuffixArray {
 36     protected: 
 37         Pair3 T1[N], T2[N];
 38         int cnt[N];
 39 
 40     public:
 41         int n;
 42         char *str;
 43         int sa[N], rk[N], hei[N];
 44 
 45         void set(int n, char* str) {
 46             this->n = n;
 47             this->str = str;
 48             memset(sa, 0, sizeof(sa));
 49             memset(rk, 0, sizeof(rk));
 50             memset(hei, 0, sizeof(hei));
 51         }
 52 
 53         void radix_sort(Pair3* x, Pair3* y) {
 54             int m = max(n, 256);
 55             memset(cnt, 0, sizeof(int) * m);
 56             for (int i = 0; i < n; i++)
 57                 cnt[x[i].y]++;
 58             for (int i = 1; i < m; i++)
 59                 cnt[i] += cnt[i - 1];
 60             for (int i = 0; i < n; i++)
 61                 y[--cnt[x[i].y]] = x[i];
 62 
 63             memset(cnt, 0, sizeof(int) * m);
 64             for (int i = 0; i < n; i++)
 65                 cnt[y[i].x]++;
 66             for (int i = 1; i < m; i++)
 67                 cnt[i] += cnt[i - 1];
 68             for (int i = n - 1; ~i; i--)
 69                 x[--cnt[y[i].x]] = y[i];
 70         }
 71 
 72         void build() {
 73             for (int i = 0; i < n; i++)
 74                 rk[i] = str[i];
 75             for (int k = 1; k < n; k <<= 1) {
 76                 for (int i = 0; i + k < n; i++)
 77                     T1[i] = Pair3(rk[i], rk[i + k], i);
 78                 for (int i = n - k; i < n; i++)
 79                     T1[i] = Pair3(rk[i], 0, i);
 80                 radix_sort(T1, T2);
 81                 int diff = 0;
 82                 rk[T1[0].id] = 0;
 83                 for (int i = 1; i < n; i++)
 84                     rk[T1[i].id] = (T1[i].x == T1[i - 1].x && T1[i].y == T1[i - 1].y) ? (diff) : (++diff);
 85                 if (diff == n - 1)
 86                     break;
 87             }
 88             for (int i = 0; i < n; i++)
 89                 sa[rk[i]] = i;
 90         }
 91 
 92         void get_height() {
 93             for (int i = 0, j, k = 0; i < n; i++, (k) ? (k--) : (0)) {
 94                 if (rk[i]) {
 95                     j = sa[rk[i] - 1];
 96                     while (i + k < n && j + k < n && str[i + k] == str[j + k])    k++;
 97                     hei[rk[i]] = k;
 98                 }
 99             }        
100         }
101 
102         const int& operator [] (int p) {
103             return sa[p];
104         }
105 
106         const int& operator () (int p) {
107             return hei[p];
108         }
109 }SuffixArray;
110 
111 int n, m, K;
112 char S[N];
113 int suf[N];
114 SuffixArray sa;
115 
116 inline boolean init() {
117     scanf("%d", &m);
118     if (!m)
119         return false;
120     K = (m >> 1) + 1;
121     scanf("%s", S);
122     n = strlen(S);
123     for (int i = 1; i < m; i++) {
124         S[n++] = '?';
125         scanf("%s", S + n);
126         n += strlen(S + n);
127     }
128     suf[n] = 0;
129     for (int i = n - 1; ~i; i--)
130         suf[i] = suf[i + 1] + (S[i] == '?');
131     sa.set(n, S);
132     return true;
133 }
134 
135 int chk_clock = 0;
136 int vis[M];
137 
138 boolean check(int L, int R, int mid) {    // [L, R)
139     if (R - L < K)
140         return false;
141     if (suf[sa[L]] - suf[sa[L] + mid])
142         return false;
143     chk_clock++;
144     int rt = 0;
145     for (int i = L; i < R && rt < K; i++)
146         if (vis[suf[sa[i]]] != chk_clock)
147             vis[suf[sa[i]]] = chk_clock, rt++;
148     return rt >= K;
149 }
150 
151 boolean check(int mid) {
152     int lst = 0;
153     boolean rt = false;
154     for (int i = 1; i < n && !rt; i++)
155         if (sa(i) < mid)
156             rt |= check(lst, i, mid), lst = i;
157     if (!rt)
158         rt |= check(lst, n, mid);
159     return rt;
160 }
161 
162 void output(int L, int R, int res) {
163     if (!check(L, R, res))
164         return;
165     for (int i = sa[L], j = 0; j < res; j++)
166         putchar(S[i + j]);
167     putchar('\n');
168 }
169 
170 inline void solve() {
171     chk_clock = 0;
172     memset(vis, 0, sizeof(vis));
173     
174     sa.build();
175     sa.get_height();
176 
177     int l = 1, r = n / m, mid;
178     while (l <= r) {
179         mid = (l + r) >> 1;
180         if (check(mid))
181             l = mid + 1;
182         else
183             r = mid - 1;
184     }
185     
186     if (!(--l))
187         puts("?");
188     else {
189         int lst = 0;
190         for (int i = 1; i < n; i++)
191             if (sa(i) < l)
192                 output(lst, i, l), lst = i;
193         output(lst, n, l);
194     }
195     puts("");
196 }
197 
198 int main() {
199     while (init())
200         solve();
201     return 0;
202 }
posted @ 2018-10-09 21:25  阿波罗2003  阅读(161)  评论(0编辑  收藏  举报