【后缀数组】 HDOJ 5008 Boring String Problem

来源:互联网 发布:pwd linux 编辑:程序博客网 时间:2024/04/25 20:31

通过后缀数组可以找到第K的串,然后用二分找到最左边的编号。。。

#include <iostream>  #include <queue>  #include <stack>  #include <map>  #include <set>  #include <bitset>  #include <cstdio>  #include <algorithm>  #include <cstring>  #include <climits>  #include <cstdlib>#include <cmath>#include <time.h>#define maxn 100005#define maxm 40005#define eps 1e-10#define mod 1000000007#define INF 999999999#define lowbit(x) (x&(-x))#define mp mark_pair#define ls o<<1#define rs o<<1 | 1#define lson o<<1, L, mid  #define rson o<<1 | 1, mid+1, R  typedef long long LL;//typedef int LL;using namespace std;LL qpow(LL a, LL b){LL res=1,base=a;while(b){if(b%2)res=res*base;base=base*base;b/=2;}return res;}LL powmod(LL a, LL b){LL res=1,base=a;while(b){if(b%2)res=res*base%mod;base=base*base%mod;b/=2;}return res;}void scanf(int &__x){__x=0;char __ch=getchar();while(__ch==' '||__ch=='\n')__ch=getchar();while(__ch>='0'&&__ch<='9')__x=__x*10+__ch-'0',__ch = getchar();}LL gcd(LL _a, LL _b){if(!_b) return _a;else return gcd(_b, _a%_b);}// headchar s[maxn];int sa[maxn], c[maxn], t1[maxn], t2[maxn];int rank[maxn], height[maxn];void build(int n, int m){    int *x = t1, *y = t2, p;    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) {        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 = 1; i < m; i++) c[i] += c[i-1];        for(int i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];        p = 1, swap(x, y), x[sa[0]] = 0;        for(int i = 1; i < n; i++)            x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i] + k] == y[sa[i-1] + k] ? p-1 : p++;        if(p >= n) break;        m = p;    }}void getheight(int n){    int k = 0;    for(int i = 0; i <= n; i++) rank[sa[i]] = i;    for(int i = 0; i < n; i++) {        if(k) k--;        int j = sa[rank[i] - 1];        while(s[i + k] == s[j + k]) k++;        height[rank[i]] = k;    }}int p[maxn];LL st1[maxn][20], st2[maxn][20];LL sum[maxn];void init(int n, int *a, LL (*t)[20]){    p[0] = -1;    for(int i = 1; i <= n; i++) p[i] = i & (i-1) ? p[i-1] : p[i-1] + 1;    for(int i = 1; i <= n; i++) t[i][0] = a[i];    for(int j = 1; j <= p[n]; j++)        for(int i = 1; i + (1 << j) - 1 <= n; i++)            t[i][j] = min(t[i][j-1], t[i + (1 << (j-1))][j-1]);}LL query(int l, int r, LL (*t)[20]){    LL k = p[r - l + 1];    return min(t[l][k], t[r - (1 << k) + 1][k]);}LL lcp(int a, int b){    if(a > b) swap(a, b);    return query(a+1, b, st1);}int find(int n, LL x){    LL bot = 0, top = n, mid, res;    while(top >= bot) {        mid = (top + bot) >> 1;        if(sum[mid] >= x) top = mid - 1, res = mid;        else bot = mid + 1;    }    return res;}int search(int pos, int n, LL k){    int bot = pos + 1, top = n, mid, res = -1;    while(top >= bot) {        mid = (top + bot) >> 1;        if(lcp(pos, mid) < k) top = mid - 1;        else bot = mid + 1, res = mid;    }    if(res != -1) return query(pos, res, st2) + 1;    return sa[pos] + 1;}void work(void){    int n = strlen(s), l, r, kk, now, tmp;LL k, v;    build(n+1, 128);    getheight(n);    init(n, height, st1);    init(n, sa, st2);    sum[0] = l = r = 0;    for(int i = 1; i <= n; i++) sum[i] = n - sa[i] - height[i];    for(int i = 1; i <= n; i++) sum[i] += sum[i-1];    scanf("%d", &kk);    while(kk--) {        scanf("%I64d", &v);        k = (l ^ r ^ v) + 1;        if(k > sum[n]) printf("0 0\n"), l = r = 0;        else {            now = find(n, k);            tmp = k - sum[now-1] + height[now];            l = min(sa[now] + 1, search(now, n, tmp));            r = l + tmp - 1;            printf("%d %d\n", l, r);        }    }}int main(void){    while(scanf("%s", s)!=EOF) work();    return 0;}


0 0
原创粉丝点击