博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

[zoj][3395][Stammering Aliens]

Posted on 2012-07-17 16:36  紫华弦筝  阅读(192)  评论(0编辑  收藏  举报

题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3971

二分答案mid,用height数组判断出现连续k次,记录出现的最大下标1,二分循环时,更新最大下标2,最后输出答案。

View Code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 40000+100;

int us[N], ua[N], ub[N], sa[N];

int cmp(int *r, int a, int b, int l){
    return r[a]==r[b] && r[a+l]==r[b+l];
}

void da(int *r, int n, int m){
    int i, j, p, *x=ua, *y=ub, *t;
    for (i=0; i<m; i++) us[i]=0;
    for (i=0; i<n; i++) us[x[i]=r[i]]++;
    for (i=1; i<m; i++) us[i]+=us[i-1];
    for (i=n-1; i>=0; i--) sa[--us[x[i]]]=i;
    for (j=1,p=1; p<n; j*=2,m=p){
        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++) us[i]=0;
        for (i=0; i<n; i++) us[x[i]]++;
        for (i=1; i<m; i++) us[i]+=us[i-1];
        for (i=n-1; i>=0; i--) sa[--us[x[y[i]]]]=y[i];
        for (t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    }
}

int rank[N], height[N], arr[N];
void calheight(int *r, 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++);
}
char str[N];

int main(){
    //freopen("D:/a.txt", "r", stdin);
    int k, n, st, ed, mid, ans, p;
    while (~scanf("%d", &k) && k){
        n = 0;
        scanf("%s", str);
        if (k==1){printf("%d 0\n", strlen(str)); continue;}
        for (int i=0; str[i]; i++)
            arr[n++] = str[i];
        arr[n] = 0;
        da(arr, n+1, 128);
        calheight(arr, n);
        ans = 0, p = -1, st = 0,ed = n;
        while (st <= ed){
            int tp = 0, flag = 0, maxi = 0;
            mid = st + (ed - st) / 2;
            for (int i=1,cnt=1; i<=n; i++){
                if (height[i]>=mid) cnt++,tp = max(tp,sa[i]);
                else cnt=1, tp=sa[i];
                if (cnt >= k){
                    flag = 1; maxi = max(maxi, tp);
                }
            }
            if (flag) ans= mid, st = mid+1, p=maxi;
            else ed = mid-1;
        }
        if (ans>0)printf("%d %d\n", ans, p);
        else puts("none");
    }
    return 0;
}