HDU 5558 Alice's Classified Message——后缀数组+set+二分+rmq

版权声明:欢迎大家转载,转载请注明出处 https://blog.csdn.net/hao_zong_yin/article/details/83247358

15合肥签到题,不会后缀自动机只能用后缀数组来凑了

我们要完成的工作是对s的每一个后缀suf[i],找以j(0<=j<i)为起点的一个子串,使得这个子串与suf[i]的公共前缀尽量长

其实后缀数组的做法挺明显的,就是对于一个后缀suf[i],首先将它前面的后缀的rank值用set保存,然后拿rank[i]在set里二分找两个与rank[i]最接近的rank,最大匹配一定在这两个rank之中,之后用rmq求一下两个区间的区间最小值得到两个匹配长度,取个最大值就行,有了这些其余的自己凑一凑就行了

.

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
const int INF = 0x3f3f3f3f;
char s[maxn];
int sa[maxn], t[maxn], t2[maxn], c[maxn], n;
void build_sa(int m) {
    int i, *x = t, *y = t2;
    for (int i = 0; i < m; i++) c[i] = 0;
    for (int i = 0; i < n; i++) c[x[i] = s[i]]++;
    for (int i = 1; i < m; i++) c[i] += c[i-1];
    for (int i = n-1; i >= 0; i--) sa[--c[x[i]]] = i;
    for (int k = 1; k <= n; k <<= 1) {
        int p = 0;
        for (int i = n-k; i < n; i++) y[p++] = i;
        for (int i = 0; i < n; i++) if (sa[i] >= k) y[p++] = sa[i]-k;
        for (int i = 0; i < m; i++) c[i] = 0;
        for (int i = 0; i < n; i++) c[x[y[i]]]++;
        for (int i = 0; i < m; i++) c[i] += c[i-1];
        for (int i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
        swap(x, y);
        p = 1; x[sa[0]] = 0;
        for (int i = 1; i < n; i++){
            x[sa[i]] = y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
        }
        if (p >= n) break;
        m = p;
    }
}
int ran[maxn], height[maxn];
void getHeight() {
    int k = 0;
    for (int i = 0; i < n; i++) ran[sa[i]] = i;
    for (int i = 0; i < n; i++) {
        if (k) k--;
        int j = sa[ran[i]-1];
        while (s[i+k] == s[j+k]) k++;
        height[ran[i]] = k;
    }
}
int dp[20][maxn];
void build_rmq() {
    for (int i = 0; i < 20; i++) {
        for (int j = 0; j < n; j++) {
            dp[i][j] = 0;
        }
    }
    for (int i = 2; i <= n; i++) dp[1][i-1] = height[i];
    int len = (int)log2(n);
    for (int i = 2; i <= len; i++) {
        for (int j = 1; j + (1<<i)-1 <= n; j++) {
            dp[i][j] = min(height[j+(1<<(i-1))], min(dp[i-1][j], dp[i-1][j+(1<<(i-1))]));
        }
    }
}
int query_rmq(int l, int r) {
    int x = (int)log2(r-l+1);
    return min(dp[x][l], dp[x][r-(1<<x)+1]);
}
set<int> se;
set<int>::iterator it1, it2;
int T;
int main() {
    scanf("%d", &T);
    for (int ks = 1; ks <= T; ks++) {
        scanf("%s", s);
        n = strlen(s);
        s[n] = '#';
        n++;
        build_sa(128);
        getHeight();
        n--;
        build_rmq();
        int pos = 0;
        se.clear();
        se.insert(-INF);
        se.insert(INF);
        printf("Case #%d:\n", ks);
        while (pos < n) {
            int k = 0, t = 0;
            it1 = it2 = se.upper_bound(ran[pos]);
            it1--;
            while (*it1 != -INF) {
                int x = query_rmq(*it1, ran[pos]);
                if (x < k || x == 0) break;
                if (x > k || (x == k && sa[*it1] < t)) {
                    k = x;
                    t = sa[*it1];
                }
                it1--;
            }
            while (*it2 != INF) {
                int x = query_rmq(ran[pos], *it2);
                if (x < k || x == 0) break;
                if (x > k || (x == k && sa[*it2] < t)) {
                    k = x;
                    t = sa[*it2];
                }
                it2++;
            }
            int old = pos;
            if (k == 0) {
                printf("%d %d\n", -1, (int)s[pos]);
                pos++;
            }
            else {
                printf("%d %d\n", k, t);
                pos += k;
            }
            for (int i = old; i < pos; i++) se.insert(ran[i]);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/hao_zong_yin/article/details/83247358