poj 3261

来源:互联网 发布:网络视频会议系统品牌 编辑:程序博客网 时间:2024/06/06 04:40

题意很简单:求最长为20000的数组里,重复次数至少为K次的最长子串;

思路: 后缀树组 + 二分 ,因为数组里的每个元素的最大值为10^6 ,就后缀数组的时候要用快排不用基数排序


http://poj.org/problem?id=3261


#include <iostream>#include <algorithm>#include <cstdio>using namespace std;const int maxn=20010;int r[maxn],wa[maxn],wb[maxn],s[maxn],v[maxn],N,K,sa[maxn];int cmp1(int a,int b){    if(r[a]==r[b]) return a < b;    return r[a] < r[b];}int cmp2(int a,int b){    if(v[a]==v[b]) return a < b;    return v[a] < v[b];}int cmp(int *p ,int x, int y, int l){    return p[x] == p[y] && p[x + l] == p[y + l];}void da(int n,int m){    int i,j,*x=wa,*y=wb,*t,p;    for(i=0;i<n;i++)      s[i]=i,x[i]=r[i];    sort(s,s+n,cmp1);    for(i=0;i<n;i++)  sa[i]=s[i];    for(p=1,j=1;p<n;j*=2,m=p)    {        for(p=0,i=n-j;i<n;i++) y[p++]=i;        for(int i=0;i<n;i++)          if(sa[i]>=j) y[p++]=sa[i]-j;        for(i=0;i<n;i++) v[i]=x[y[i]];        for(i=0;i<n;i++) s[i]=i;        sort(s,s+n,cmp2);        for(i = 0; i < n; i++) sa[i] = y[s[i]];        for(t=x,x=y,y=t,i=1,p=1,x[sa[0]] = -1;i<n;i++)          x[sa[i]]=cmp(y, sa[i - 1], sa[i], j) ? p - 1: p ++;    }}int rank[maxn],height[maxn];void cal_height(int n){    int i,j,k;    for(i=0;i<=n;i++) rank[sa[i]]=i;    for(i=0,k=0;i<n;height[rank[i++]]=k)      for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);}void solve(){    da(N+1,1001000);    cal_height(N);  //  for(int i=0;i<=N;i++) cout<<height[i]<<"  ";  //  cout<<endl;    int l=1,r=N,mid,ans=1;    while(l<=r)    {        mid=(l+r)>>1;        bool ok=0;        for(int i=1,j=1;i<=N;i++)          if(height[i]<mid) j=i;          else if(i-j+1>=K) { ok=1;break; }        if(ok)        {            ans=mid; l=mid+1;        }        else  r=mid-1;    }    printf("%d\n",ans);}int main(){    while(scanf("%d%d",&N,&K)==2)    {        for(int i=0;i<N;i++)          scanf("%d",r+i);        r[N]=-1;        if(K==1) printf("%d\n",N);        else           solve();    }    return 0;}



原创粉丝点击