P2852 [USACO06DEC]牛奶模式Milk Patterns

//Pro: P2852 [USACO06DEC]牛奶模式Milk Patterns

//后缀数组 
//求出现次数>=k的最长可重叠字串的长度 
//首先出现次数为k+1的串的长度肯定不大于出现次数为k的串
//所以我们就求出现次数为k次的串 
//我们把这个串看成是原串的后缀的前缀
//那么这个串就是k个后缀的前缀
//而且这k个后缀的rnk是连续的
//又因为height[i]记录的是sa[i]与sa[i-1]的lcp
//所以我们找k-1个连续的height,就找到了rnk连续的k个后缀
//而这k个后缀的height的最小值就是一个满足“出现次数>=k次”的子串的长度
//我们要求的就是所有连续k-1个height的最小值的最大值 
//单调队列维护一下 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

inline int read()
{
    char c=getchar();int num=0;
    for(;!isdigit(c);c=getchar());
    for(;isdigit(c);c=getchar())
        num=num*10+c-'0';
    return num;
}

const int N=2e4+5;

int n,k,m;
int a[N],b[N];
int rnk[N],sa[N],tp[N],tax[N],height[N];

inline void Qsort()
{
    for(int i=1;i<=m;++i)
        tax[i]=0;
    for(int i=1;i<=n;++i)
        ++tax[rnk[i]];
    for(int i=1;i<=m;++i)
        tax[i]+=tax[i-1];
    for(int i=n;i;--i)
        sa[tax[rnk[tp[i]]]--]=tp[i];
}

void Suffix_sort()
{
    for(int i=1;i<=n;++i)
        rnk[i]=a[i],tp[i]=i;
    Qsort();
    for(int l=1,p=0;p<n;m=p,l<<=1)
    {
        p=0;
        for(int i=n-l+1;i<=n;++i)
            tp[++p]=i;
        for(int i=1;i<=n;++i)
            if(sa[i]>l)
                tp[++p]=sa[i]-l;
        Qsort();
        swap(tp,rnk);
        rnk[sa[1]]=p=1;
        for(int i=2;i<=n;++i)
            rnk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+l]==tp[sa[i-1]+l])?p:++p;
    }
}

void Get_height()
{
    int j,k=0;
    for(int i=1;i<=n;++i)
    {
        if(k)
            --k;
        j=sa[rnk[i]-1];
        while(a[i+k]==a[j+k])
            ++k;
        height[rnk[i]]=k;
    }
}

int que[N],head,tail;
int main()
{
    n=read(),k=read();
    for(int i=1;i<=n;++i)
        a[i]=read(),b[i]=a[i];
    sort(b+1,b+n+1);
    m=unique(b+1,b+n+1)-b;
    for(int i=1;i<=n;++i)
        a[i]=lower_bound(b+1,b+m,a[i])-b;
    Suffix_sort();
    Get_height();
    int ans=0;
    head=1;
    for(int i=1;i<=n;++i)
    {
        while(head<=tail&&que[head]<=i-k+1)
            ++head;
        while(head<=tail&&height[que[tail]]>=height[i])
            --tail;
        que[++tail]=i;
        if(i>=k)
            ans=max(ans,height[que[head]]);
    }
    cout<<ans;
    return 0;
}
原文地址:https://www.cnblogs.com/lovewhy/p/9633632.html