UVA11107 Life Forms
题目描述:
求出出现在一半以上的字符串内的最长字符串。
数据范围:
\(\sum len(string) <= 10^{5}\)
非常坑的题目。
思路非常好想。
构造出后缀数组。
二分出\(len\)后用\(height\)分组
记\(bel(i)\)表示排名为\(i\)后缀属于哪一个串
当同一组内的不同的\(bel(i)\)出现了\(n/2\)时,本组内有一组解。
注意:
每行数据间要打一个空行
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <cstdio>
#include <cstring>
#include <iostream>
#define sid 200050
#define ri register int
using namespace std;
template <typename re>
inline void upmax(re &a, re b) { if(a < b) a = b; }
int Tt, n, ml, ned;
char s[sid];
int bel[sid], sc[sid];
int flag[200];
int sa[sid], rk[sid], cnt[sid], p1[sid], p2[sid], ht[sid];
inline void Suffix() {
int m = 128;
int *t1 = p1, *t2 = p2;
for(ri i = 1; i <= n; i ++) sc[i] = (s[i] == 1) ? ++ m : s[i];
for(ri i = 1; i <= n; i ++) t1[i] = sc[i];
for(ri i = 1; i <= m; i ++) cnt[i] = 0;
for(ri i = 1; i <= n; i ++) cnt[t1[i]] ++;
for(ri i = 1; i <= m; i ++) cnt[i] += cnt[i - 1];
for(ri i = n; i >= 1; i --) sa[cnt[t1[i]] --] = i;
for(ri k = 1; k <= n; k <<= 1) {
int p = 0;
for(ri i = 0; i <= m; i ++) t2[i] = 0;
for(ri i = n - k + 1; i <= n; i ++) t2[++ p] = i;
for(ri i = 1; i <= n; i ++) if(sa[i] > k) t2[++ p] = sa[i] - k;
for(ri i = 1; i <= m; i ++) cnt[i] = 0;
for(ri i = 1; i <= n; i ++) cnt[t1[t2[i]]] ++;
for(ri i = 1; i <= m; i ++) cnt[i] += cnt[i - 1];
for(ri i = n; i >= 1; i --) sa[cnt[t1[t2[i]]] --] = t2[i];
swap(t1, t2); t1[sa[1]] = p = 1;
for(ri i = 2; i <= n; i ++)
t1[sa[i]] = (t2[sa[i]] == t2[sa[i - 1]] && t2[sa[i] + k] == t2[sa[i - 1] + k]) ? p : ++ p;
m = p; if(p >= n) break;
}
for(ri i = 1; i <= n; i ++) rk[sa[i]] = i;
ri k = 1, j;
for(ri i = 1; i <= n; i ++) {
if(k) k --;
j = sa[rk[i] - 1];
while(sc[j + k] == sc[i + k]) k ++;
ht[rk[i]] = k;
}
}
inline bool Check(int htk) {
int cnt = 0, tim = 0;
memset(flag, 0, sizeof(flag));
for(ri i = 1; i <= n; i ++) {
if(ht[i] < htk) cnt = 0, ++ tim;
if(flag[bel[sa[i]]] != tim && bel[sa[i]]) cnt ++, flag[bel[sa[i]]] = tim;
if(cnt >= ned) return 1;
}
return 0;
}
inline int Binary() {
int l = 1, r = ml, ans = -1;
while(l <= r) {
int mid = (l + r) >> 1;
if(Check(mid)) l = mid + 1, ans = mid;
else r = mid - 1;
}
return ans;
}
inline void Get_Ans(int op) {
if(op == -1) {
printf("?\n");
return;
}
memset(flag, 0, sizeof(flag));
int cnt = 0, tim = 0, fag;
for(ri i = 1; i <= n; i ++) {
if(ht[i] < op) fag = 0, cnt = 0, ++ tim;
if(flag[bel[sa[i]]] != tim && bel[sa[i]]) cnt ++, flag[bel[sa[i]]] = tim;
if(cnt >= ned && !fag) {
int k = sa[i];
for(ri j = 1; j <= op; j ++) printf("%c", s[k + j - 1]);
printf("\n");
cnt = 0; fag = 1;
}
}
}
int main() {
bool pe = 0;
while(scanf("%d", &Tt) == 1 && Tt) {
if(pe) printf("\n"); pe = 1;
n = ml = 0; ned = Tt / 2 + 1;
memset(s, 0, sizeof(s));
memset(bel, 0, sizeof(bel));
for(ri i = 1; i <= Tt; i ++) {
scanf("%s", s + 1 + n);
int nl = strlen(s + 1 + n);
for(ri j = n + 1; j <= n + nl; j ++) bel[j] = i;
upmax(ml, nl); n += nl; s[++ n] = 1;
}
if(Tt != 1) {
Suffix();
int ans = Binary();
Get_Ans(ans);
}
else {
for(ri j = 1; j <= n - 1; j ++) printf("%c", s[j]);
printf("\n");
}
}
return 0;
}