POJ 3261 Milk Patterns 后缀数组

Description

Farmer John has noticed that the quality of milk given by his cows varies from day to day. On further investigation, he discovered that although he can't predict the quality of milk from one day to the next, there are some regular patterns in the daily milk quality.

To perform a rigorous study, he has invented a complex classification scheme by which each milk sample is recorded as an integer between 0 and 1,000,000 inclusive, and has recorded data from a single cow over N (1 ≤ N ≤ 20,000) days. He wishes to find the longest pattern of samples which repeats identically at least K (2 ≤ K ≤ N) times. This may include overlapping patterns -- 1 2 3 2 3 2 3 1 repeats 2 3 2 3 twice, for example.

Help Farmer John by finding the longest repeating subsequence in the sequence of samples. It is guaranteed that at least one subsequence is repeated at least K times.

Input

Line 1: Two space-separated integers:  N and  K 
Lines 2.. N+1:  N integers, one per line, the quality of the milk on day  i appears on the  ith line.

Output

Line 1: One integer, the length of the longest pattern which occurs at least  K times

Sample Input

8 2
1
2
3
2
3
2
3
1

Sample Output

4

这道题说的是求一个串长度最长的且可重叠出现k次的子串

也是一个后缀数组的板题。。。

首先建立一个后缀数组,然后把height求出来。

二分答案ans,也就是变成了是否有一组后缀的lcp都在ans以上且这些后缀的个数大于k


对了,我还有一点要说,明明题目中说了1000000,为什么那么多人还用计数排序呀!

神TM,你好歹也看看数据范围不要直接套版,不然加一个离散化也好呀,各种博客都没给说明,想都不想直接套版,AC了事写个鬼博客

虽然数据水你也不能这么干

因此我用的是归并排序,调用库函数stable_sort代替给第一关键字排序的计数排序,理由是这两个都是稳定的,可以保证不会打乱第二关键字的顺序

以上

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int maxm=20010;

int n,k,wa[maxm],wb[maxm],raw[maxm],sa[maxm],*x,*y,height[maxm],_rank[maxm];
void da(),calheight();
bool cmp(int* r,int a,int b,int L){return r[a]==r[b]&&r[a+L]==r[b+L];}
bool cmp2(int a,int b){return x[a]<x[b];}
bool judge(int mid);

int main(){
    ios_base::sync_with_stdio(false);
    while(cin>>n>>k){
        for(int i=0;i<n;++i)
            cin>>raw[i];
        raw[n++]=-1;
        da();
        calheight();
        int le=1,ri=n-1;
        while(ri>le+1){(judge((le+ri)>>1)?le:ri)=(le+ri)>>1;}
        cout<<((le==ri||judge(ri))?ri:le)<<endl;
    }
    return 0;
}

void da(){
    int i,j,p;
    x=wa,y=wb;
    for(i=0;i<n;++i)
        sa[i]=i,x[i]=raw[i];

    stable_sort(sa,sa+n,cmp2);
    for(j=1,p=1;p<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<n;++i)sa[i]=y[i];
        stable_sort(sa,sa+n,cmp2);
        for(swap(x,y),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++;
    }
}

void calheight(){
    for(int i=0;i<n;++i)_rank[sa[i]]=i;
    for(int i=0,j,k=0;i<n;height[_rank[i++]]=k)
    for(k?k--:0,j=sa[_rank[i]-1];raw[i+k]==raw[j+k];++k);
}

bool judge(int mid){
    int num=1;
    for(int i=0;i<n;++i){
        if(height[i]>=mid)
            ++num;
        else
            num=1;
        if(num>=k)
            return true;
    }
    return false;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值