Suffix Array Poj 1743

Musical Theme

Question

求字符串中不重叠重复出现的最长子串长度


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define For(i,s,e) for(int i=(s); i<=(e); i++)
#define Rep(i,s,e) for(int i=(s); i>=(e); i--)
using namespace std;

const int N = 20000 + 1, Base = 100;

int n, a[N], s[N], x[N], y[N], tmp[N], buc[N], Sa[N], Rank[N], H[N];

void getSa(int* x, int* y, int m){
    For(i, 0, m - 1) buc[i] = 0;
    For(i, 0, n - 1) buc[x[i] = s[i]]++;
    For(i, 1, m - 1) buc[i] += buc[i - 1];
    Rep(i, n - 1, 0) Sa[--buc[s[i]]] = i;

    for(int j = 1, p; j <= n; j <<= 1){
        p = 0;

        Rep(i, n - 1, n - j) y[p++] = i;
        For(i, 0, n - 1) if(Sa[i] >= j) y[p++] = Sa[i] - j;

        For(i, 0, n) tmp[i] = x[y[i]];
        For(i, 0, m - 1) buc[i] = 0;
        For(i, 0, n - 1) buc[tmp[i]]++;
        For(i, 1, m - 1) buc[i] += buc[i - 1];
        Rep(i, n - 1, 0) Sa[--buc[tmp[i]]] = y[i];

        swap(x, y);  p = 1; x[Sa[0]] = 0;
        For(i, 1, n - 1){
            if(y[Sa[i]] == y[Sa[i - 1]] && y[Sa[i] + j] == y[Sa[i - 1] + j]) x[Sa[i]] = p - 1;
            else x[Sa[i]] = p++;
        }
        if(p >= n) break;
        m = p;
    }
}
void getHeight(){
    For(i, 0, n - 1) Rank[Sa[i]] = i;
    int k = 0;
    For(i, 0, n - 1){
        if(!Rank[i]) continue;
        if(k) k--;
        int j = Sa[Rank[i] - 1];
        while(s[i + k] == s[j + k]) k++;
        H[Rank[i]] = k;
    }
}

bool can(int l){
    int Max = 0, Min = n;
    For(i, 0, n - 1){
        if(H[i] < l){
            if(Max - Min > l) return true;
            Max = Sa[i], Min = Sa[i];
        } else {
            Max = max(Max, Sa[i]);
            Min = min(Min, Sa[i]);
        }
    }
    return Max - Min > l;
}

int main(){
    freopen("test.in","r",stdin);
    freopen("test.out","w",stdout);

    while(scanf("%d",&n), n){
        memset(Sa, 0, sizeof(Sa));
        memset(H, 0, sizeof(H));

        For(i, 0, n - 1) scanf("%d",&a[i]);
        For(i, 1, n - 1) s[i] = a[i] - a[i - 1] + Base;//根据原题要求差分

        getSa(x, y, 200), getHeight();

        int l = 1, r = N + 1, mid, Ans;
        while(l < r){
            mid = (l + r + 1) >> 1;
            if(can(mid)) l = mid;
            else r = mid - 1;
        }
        printf("%d\n",l + 1 < 5 ? 0  : l + 1);
    }

    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值