【bzoj】1717 [Usaco2006 Dec]Milk Patterns 产奶的模式

【算法】后缀数组

【题解】后缀数组

由于m太大,先离散化。

然后处理SA和LCP。

最后用单调队列处理即可。

注意实际上队列头尾长度限制是K-1.

删队尾不要删过头

i≥K才能开始统计答案。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=20010;
int n,m,s[maxn],x[maxn],y[maxn],base[maxn],sa[maxn],h[maxn],K,q[maxn];
struct lshs{int ord,num;}lsh[maxn];
bool cmp(lshs a,lshs b)
{return a.num<b.num;}
void build_sa(int m)
{
    for(int i=1;i<=m;i++)base[i]=0;
    for(int i=1;i<=n;i++)base[x[i]=s[i]]++;
    for(int i=2;i<=m;i++)base[i]+=base[i-1];
    for(int i=n;i>=1;i--)sa[base[x[i]]--]=i;
    for(int k=1;k<=n;k<<=1)
     {
         int p=0;
         for(int i=n-k+1;i<=n;i++)y[++p]=i;
         for(int i=1;i<=n;i++)if(sa[i]>k)y[++p]=sa[i]-k;
         for(int i=1;i<=m;i++)base[i]=0;
         for(int i=1;i<=n;i++)base[x[i]]++;
         for(int i=2;i<=m;i++)base[i]+=base[i-1];
         for(int i=n;i>=1;i--)sa[base[x[y[i]]]--]=y[i];
         swap(x,y);
         p=1;x[sa[1]]=1;
         for(int i=2;i<=n;i++)
          x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p:++p;
         if(p>=n)break;
         m=p;
     }
    int k=0;
    for(int i=1;i<=n;i++)
     {
         if(k)k--;
         int j=sa[x[i]-1];
         while(s[i+k]==s[j+k])k++;
         h[x[i]]=k;
     }
}
int main()
{
    scanf("%d%d",&n,&K);
    for(int i=1;i<=n;i++)
     {
         scanf("%d",&lsh[i].num);
         lsh[i].ord=i;
     }
    sort(lsh+1,lsh+n+1,cmp);
    int p=1;s[lsh[1].ord]=1;
    for(int i=2;i<=n;i++)s[lsh[i].ord]=lsh[i].num==lsh[i-1].num?p:++p;
    build_sa(p);
    K--;
    int head=0,tail=0;
    int ans=0;
    for(int i=2;i<=n;i++)
     {
         while(h[q[tail-1]]>h[i]&&tail>head)tail--;
         q[tail++]=i;
         if(i-q[head]>=K)head++;
         if(i>=K+1)ans=max(ans,h[q[head]]);
     }
    printf("%d",ans);
    return 0;
}
View Code

 

posted @ 2017-04-03 16:36  ONION_CYC  阅读(214)  评论(0编辑  收藏  举报