首页 > 代码库 > HUID 5558 Alice's Classified Message 后缀数组+单调栈+二分

HUID 5558 Alice's Classified Message 后缀数组+单调栈+二分

http://acm.hdu.edu.cn/showproblem.php?pid=5558

对于每个后缀suffix(i),想要在前面i - 1个suffix中找到一个pos,使得LCP最大。这样做O(n^2)

考虑到对于每一个suffix(i),最长的LCP肯定在和他排名相近的地方取得。

按排名大小顺序枚举位置,按位置维护一个递增的单调栈,对于每一个进栈的元素,要算一算栈内元素和他的LCP最大是多少。

如果不需要输出最小的下标,最大的直接是LCP(suffix(st[top]),  suffix(st[top - 1]))就是相邻的两个。

但是要求最小的下标,这样的话需要对整个栈进行一个遍历,找到下标最小的并且长度最大的。整个栈与新进来的栈顶元素的LCP存在单调性,单调递增,所以可以二分。

技术分享
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <string>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#define X first
#define Y second
#define clr(u,v); memset(u,v,sizeof(u));
#define in() freopen("data.txt","r",stdin);
#define out() freopen("ans","w",stdout);
#define Clear(Q); while (!Q.empty()) Q.pop();
#define pb push_back
#define inf (0x3f3f3f3f)
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int maxn = 100000 + 2;
int sa[maxn], x[maxn], y[maxn], book[maxn];
bool cmp(int r[], int a, int b, int len) {
    return r[a] == r[b] && r[a + len] == r[b + len];
}
void da(char str[], int sa[], int lenstr, int mx) {
    int *fir = x, *sec = y, *ToChange;
    for (int i = 0; i <= mx; ++i) book[i] = 0;
    for (int i = 1; i <= lenstr; ++i) {
        fir[i] = str[i];
        book[str[i]]++;
    }
    for (int i = 1; i <= mx; ++i) book[i] += book[i - 1];
    for (int i = lenstr; i >= 1; --i) sa[book[fir[i]]--] = i;
    for (int j = 1, p = 1; p <= lenstr; j <<= 1, mx = p) {
        p = 0;
        for (int i = lenstr - j + 1; i <= lenstr; ++i) sec[++p] = i;
        for (int i = 1; i <= lenstr; ++i) {
            if (sa[i] > j)
                sec[++p] = sa[i] - j;
        }
        for (int i = 0; i <= mx; ++i) book[i] = 0;
        for (int i = 1; i <= lenstr; ++i) book[fir[sec[i]]]++;
        for (int i = 1; i <= mx; ++i) book[i] += book[i - 1];
        for (int i = lenstr; i >= 1; --i) sa[book[fir[sec[i]]]--] = sec[i];
//        ToChange = fir, fir = sec, sec = ToChange;
        swap(fir, sec);
        fir[sa[1]] = 0;
        p = 2;
        for (int i = 2; i <= lenstr; ++i) {
            fir[sa[i]] = cmp(sec, sa[i - 1], sa[i], j) ? p - 1 : p++;
        }
    }
}
int height[maxn], RANK[maxn];
void calcHight(char str[], int sa[], int lenstr) {
    for (int i = 1; i <= lenstr; ++i) RANK[sa[i]] = i;
    int k = 0;
    for (int i = 1; i <= lenstr - 1; ++i) {
        k -= k > 0;
        int j = sa[RANK[i] - 1];
        while (str[j + k] == str[i + k]) ++k;
        height[RANK[i]] = k;
    }
}
char str[maxn];
int dp[maxn][19];
vector<int> fuck[26];
const int need = 18;
void init_RMQ(int n, int a[]) {
    for (int i = 1; i <= n; ++i) {
        dp[i][0] = a[i];
    }
    for (int j = 1; j < need; ++j) {
        for (int i = 1; i + (1 << j) - 1 <= n; ++i) {
            dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
        }
    }
}
int ask(int be, int en) {
    if (be > en) swap(be, en);
    be++;
    int k = (int)log2(en - be + 1);
    return min(dp[be][k], dp[en - (1 << k) + 1][k]);
}
int f;
int st[maxn], top;
int t[maxn];
int ans[maxn], id[maxn];
bool check(int pos, int len) {
    int res = ask(RANK[st[pos]], RANK[st[top]]);
    return res == len;
}
void work() {
    memset(ans, 0, sizeof ans);
    memset(id, 0x3f, sizeof id);
    scanf("%s", str + 1);
    int lenstr = strlen(str + 1);
    str[lenstr + 1] = $;
    str[lenstr + 2] = \0;
    da(str, sa, lenstr + 1, 128);
    calcHight(str, sa, lenstr + 1);
//    for (int i = 1; i <= lenstr + 1; ++i) {
//        printf("%d ", sa[i]);
//    }
//    printf("\n");
    init_RMQ(lenstr + 1, height);
    printf("Case #%d:\n", ++f);
    top = 0;
    for (int i = 2; i <= lenstr + 1; ++i) {
        while (top >= 1 && sa[i] < st[top]) {
            top--;
        }
        st[++top] = sa[i];
        if (top >= 2) {
            int tlen = ask(RANK[st[top]], RANK[st[top - 1]]);
            ans[st[top]] = tlen;
            id[st[top]] = st[top - 1];
            int be = 1, en = top - 2;
            while (be <= en) {
                int mid = (be + en) >> 1;
                if (check(mid, tlen)) en = mid - 1;
                else be = mid + 1;
            }
            id[st[top]] = st[be];
        }
    }
//    for (int i = 1; i <= lenstr; ++i) {
//        printf("%d ", ans[i]);
//    }
//    printf("\n");

    top = 0;
    for (int i = lenstr + 1; i >= 2; --i) {
        while (top >= 1 && sa[i] < st[top]) {
            top--;
        }
        st[++top] = sa[i];
        if (top >= 2) {
            int tlen = ask(RANK[st[top]], RANK[st[top - 1]]);
            if (ans[st[top]] < tlen) {
                ans[st[top]] = tlen;
                id[st[top]] = st[top - 1];
            } else if (ans[st[top]] == tlen && id[st[top]] > st[top - 1]) {
                id[st[top]] = st[top - 1];
            } else if (ans[st[top]] > tlen) continue; // 太小了
            int be = 1, en = top - 2;
            while (be <= en) {
                int mid = (be + en) >> 1;
                if (check(mid, tlen)) en = mid - 1;
                else be = mid + 1;
            }
            if (check(be, tlen)) 
                id[st[top]] = min(id[st[top]], st[be]);
        }
    }
//    for (int i = 1; i <= lenstr; ++i) {
//        printf("%d ", ans[i]);
//    }
//    printf("\n");
    for (int i = 1; i <= lenstr;) {
        if (ans[i] == 0) {
            printf("%d %d\n", -1, str[i]);
            i++;
        } else {
            printf("%d %d\n", ans[i], id[i] - 1);
            i += ans[i];
        }
    }
}
int main()
{
#ifdef local
    in();
#else
#endif
//    printf("%d\n", 1 << 17);
    int t;
    scanf("%d", &t);
    while (t--) work();
    return 0;
}
View Code

 

HUID 5558 Alice's Classified Message 后缀数组+单调栈+二分