UVA11107 Life Forms --- 后缀数组

UVA11107 Life Forms

题目描述:

求出出现在一半以上的字符串内的最长字符串。

数据范围:

(sum len(string) <= 10^{5})

非常坑的题目。

思路非常好想。

构造出后缀数组。

二分出(len)后用(height)分组

记(bel(i))表示排名为(i)后缀属于哪一个串

当同一组内的不同的(bel(i))出现了(n/2)时,本组内有一组解。

注意:

每行数据间要打一个空行

#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("?
");
        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("
");
            cnt = 0; fag = 1;
        }
    }
}

int main() {
    bool pe = 0;
    while(scanf("%d", &Tt) == 1 && Tt) {
        if(pe) printf("
"); 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("
");
        }
    }
    return 0;
}
打开有惊喜
原文地址:https://www.cnblogs.com/reverymoon/p/8971188.html