poj 3261

题意很简单:求最长为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;
}



你可能感兴趣的:(poj 3261)