• 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;
    }
  • 相关阅读:
    Tarjan算法与割点割边
    kmp匹配
    最小表示法
    字典树
    哈希
    网络流入门浅谈
    关于两道搜索的题目
    2020 4.2校内测题解
    LIS最长上升子序列讲解&&洛谷P1439 【模板】最长公共子序列 题解
    浅谈拉格朗日插值公式
  • 原文地址:https://www.cnblogs.com/lovewhy/p/9633632.html
Copyright © 2020-2023  润新知