POJ 1743

Musical Theme

用了一个星期的时间学了一下后缀数组,然后将罗穗骞论文上的题目都做完。有些题写起来太蛋碎了。。。

这道题是论文上的第一道题目,还是蛮简单的。。直接二分长度l,利用height数组将后缀分组,然后判断同组的是不是存在排名第i和j的后缀使得abs(sa[i] - sa[j]) >= l。


#include 
#define maxn 20005

int r[maxn], sa[maxn], height[maxn],rank[maxn];
int wa[maxn], wb[maxn], wv[maxn], ws[maxn];

bool cmp(int *arr, int x, int y, int l){
    return arr[x]==arr[y]&&arr[x+l]==arr[y+l];
}

void da(int *r, int * sa, int n, int m){
    int i, j, p, *x = wa, *y = wb, *t;

    for(i = 0; i < m; i ++) ws[i] = 0;
    for(i = 0; i < n; i ++) ws[x[i] = r[i]] ++;
    for(i = 1; i < m; i ++) ws[i] += ws[i-1];
    for(i = n-1; i >= 0; i --) sa[--ws[x[i]]] = i;

    for(j = 1; j <= n; j<<=1){
        for(p = 0, i = n - j; i < n; i ++)  y[p ++] = i;
        for(i = 0; i < n; i ++) if(sa[i] >= j)  y[p ++] = sa[i] - j;

        for(i = 0; i < m; i ++) ws[i] = 0;
        for(i = 0; i < n; i ++) ws[wv[i] = x[y[i]]] ++;
        for(i = 1; i < m; i ++) ws[i] += ws[i-1];
        for(i = n-1; i >= 0; i --) sa[--ws[wv[i]]] = y[i];

        t = x, x = y, y = t;
        p = 1, x[sa[0]] = 0;
        for(i = 1; i < n; i ++)
            x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1 : p ++;
        if(p >= n) break;
        m = p;
    }
}

void calcHeight(int *r ,int *sa, int n){
    int i, j, k = 0;
    for(i = 1; i <= n; i ++)    rank[sa[i]] = i;
    for(i = 0; i < n; height[rank[i ++]] = k)
        for(k?k-- : 0, j = sa[rank[i]-1]; r[i+k]==r[j+k]; k ++);
}

bool check(int b,int n){
    int ex = sa[1], ey = sa[1];
    for(int i = 2; i <= n; i ++){
        if(height[i] < b){
            ex = sa[i], ey = sa[i];
        }
        else{
            if(ex > sa[i]) ex = sa[i];
            if(ey < sa[i]) ey = sa[i];
            if(ey - ex >= b)
                return true;
        }
    }
    return false;
}
int main(){
    int n, x, y, i;
    while(scanf("%d", &n), n){
        n --;
        scanf("%d", &x);
        for(i = 0; i < n; i ++){
            scanf("%d", &y);
            r[i] = y - x + 100;
            x = y;
        }
        r[n] = 0;
        da(r, sa, n+1, 200);
        calcHeight(r, sa, n);
        int l = 0, r = n/2, mid;
        while(l <= r){
            mid = (r + l)/2;
            if(check(mid, n))
                l = mid + 1;
            else
                r = mid - 1;
        }
        printf("%d\n", r >= 4 ? r + 1: 0);
    }
    return 0;
}


你可能感兴趣的:(后缀数组,POJ,二分查找)