HLG 1543 序列难题[后缀数组]

题意:

给出长度为n的数字序列,求重复出现次数不小于k的最长序列(连续)的长度。
例如序列 1 2 3 2 3 2 3 1,k=2,那么序列2 3 2 3重复出现了两次,长度为4。
分析:
二分枚举长度,如果在height数组中连续出现超过k次的话就满足。
View Code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 1000002;
int s[maxn];
int sa[maxn],t[maxn],t2[maxn],c[maxn];
int N;

void build_sa(int n,int m)
{
    int i, *x=t, *y=t2;

    for (i=0; i<m; i++) c[i] = 0;
    for (i=0; i<n; i++) c[x[i] = s[i]]++;
    for (i=1; i<m; i++) c[i] += c[i-1];
    for (i=n-1; i>=0; i--) sa[--c[x[i]]] = i;
    int p;
    for (int k=1; k<=n; k<<=1) {
        p = 0;
        for (i=n-k; i<n; i++) y[p++] = i;
        for (i=0; i<n; i++) if (sa[i] >= k) y[p++] = sa[i]-k;
        for (i=0; i<m; i++) c[i] = 0;
        for (i=0; i<n; i++) c[x[y[i]]]++;
        for (i=0; i<m; i++) c[i] += c[i-1];
        for (i=n-1; i>=0; i--) sa[--c[x[y[i]]]] = y[i];
        swap(x, y);
        p = 1; x[sa[0]] = 0;
        for (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 rank[maxn],height[maxn];


void getheight()
{

    int i, j, k = 0;
    for (i=1; i<=N; i++) rank[sa[i]] = i;
    for (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;
    }
}

bool ok(int len, int k)
{
    int i;
    int tot = 1;
    for (i=1; i<=N; i++){
        if ( height[i] >= len){
            tot++;
            if (tot >= k)
                return true;
        }
        else tot = 1;
    }
    return false;
}

void solve(int k)
{
    int i, j;
    int l, r, mid, res;
    l = k; r = N;
    while (l <= r){
        mid = (l+r)/2;
        if (ok(mid, k)){
            res = mid;
            l = mid+1;
        }
        else r = mid-1;
    }
    printf("%d\n",res);
}
int main()
{
   //  freopen("in.in","r",stdin);
    int k, i;
    while (scanf("%d %d",&N,&k)!=EOF)
    {
        for (i=0; i<N; i++){
            scanf("%d", &s[i]);
        }

        build_sa(N+1,20001);// N+1之后,sa下标就是从1开始了
        getheight();
        solve(k);
    }
    return 0;
}

 

posted @ 2013-02-13 21:30  'wind  阅读(254)  评论(0编辑  收藏  举报