• BZOJ#1717:[Usaco2006 Dec]Milk Patterns 产奶的模式(后缀数组+单调队列)


     

    1717: [Usaco2006 Dec]Milk Patterns 产奶的模式


    Description

    农夫John发现他的奶牛产奶的质量一直在变动。经过细致的调查,他发现:虽然他不能预见明天产奶的质量,但连续的若干天的质量有很多重叠。我们称之为一个“模式”。 John的牛奶按质量可以被赋予一个0到1000000之间的数。并且John记录了N(1<=N<=20000)天的牛奶质量值。他想知道最长的出现了至少K(2<=K<=N)次的模式的长度。比如1 2 3 2 3 2 3 1 中 2 3 2 3出现了两次。当K=2时,这个长度为4。


    Input

    * Line 1: 两个整数 N,K。

    * Lines 2..N+1: 每行一个整数表示当天的质量值。


    Output

    * Line 1: 一个整数:N天中最长的出现了至少K次的模式的长度


    Sample Input

    8 2
    1
    2
    3
    2
    3
    2
    3
    1

    Sample Output

    4

    题解:


       看到网上基本上都是用的二分,所以我打算来一篇单调队列的做法!
     

    题意:
         题目要求满足重复k次,并且是最长的串的长度;
     

    分析:
         首先我们要知道不相邻的两个串的LCP是等于它们之间的height值的最小值(LCP定义);其次我们可以发现这样一个性质,假设:
       A
       B
       C
       D
          E
       price:以每个串为开头,长度为k的队列的值;
      
    (根据SA数组从小到大排列的height数组)且此时k=2,如果参与答案中的最后一个串为E,那么答案就是D到E之间的
     
    height值的最小值;再假设最后一个串为B,那么答案为A到B之间的height值的最小值;到这里你有没有一点点头绪呢?^_^ 我
     
    们的答案就是在以每个串为头(或者尾),以k为身长的一个队列中,再根据上面的性质,每个price是它队身中height值的最小
     
    值;我们只要找出最小的price就是我们的答案了! 可能你会问不是要求至少吗?其实你可以想想,我们在已经满足了k的条件
     
    后,如果我们再继续增加队身的长度,如果进来的一个height比当前的price大,那么的对我们的price没有影响(因为上面的性
     
    质);如果来一个height比当前price小,那么会我们的price变小,这不符合我们的需要,所以证明;所以我们只需要O(n)的进
     
    行单调队列维护最小值,求得一个最小的price即可!
     

    注意:
        因为数据可能很大,所以需要离散化一下!
     

    代码:
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    int len,m,ki;
    int str[20010];
    int rank[20010],buc[20010],SA[20010],y[20010];
    int belong[1000010],cnt;
    void suffix()
    {
        m=len;
        for(int i=0;i<m;i++) buc[i]=0;
        for(int i=0;i<len;i++) buc[rank[i]=belong[str[i]]]++;
        for(int i=1;i<m;i++) buc[i]+=buc[i-1];
        for(int i=len-1;i>=0;i--) SA[--buc[rank[i]]]=i;
        for(int k=1;k<len;k<<=1)
        {
            int p=0;
            for(int i=len-1;i>=len-k;i--) y[p++]=i;
            for(int i=0;i<len;i++) if(SA[i]>=k) y[p++]=SA[i]-k;
            for(int i=0;i<m;i++) buc[i]=0;
            for(int i=0;i<len;i++) buc[rank[y[i]]]++;
            for(int i=1;i<m;i++) buc[i]+=buc[i-1];
            for(int i=len-1;i>=0;i--) SA[--buc[rank[y[i]]]]=y[i];
            swap(rank,y);p=1;
            rank[SA[0]]=0;
            for(int i=1;i<len;i++)
            {
                if(y[SA[i-1]]==y[SA[i]]&&y[SA[i-1]+k]==y[SA[i]+k])
                rank[SA[i]]=p-1;
                else rank[SA[i]]=p++;
            }
            if(p>=len) break;
            m=p;
        }
    }
    int height[20010];
    struct node
    {
        int place,price;
    }t[20010];
    
    int main()
    {
        freopen("a.in","r",stdin);
        scanf("%d%d",&len,&ki);
        int imax=0;
        for(int i=0;i<len;i++) 
        {
            scanf("%d",&str[i]);
            belong[str[i]]++;
            imax=max(str[i],imax);
        }
        for(int i=0;i<=imax;i++) if(belong[i]) belong[i]=cnt++;
        suffix();
        int x=0;
        for(int i=0;i<len;i++) rank[SA[i]]=i;
        for(int i=0;i<len;i++)
        {
            if(rank[i]==0) continue;
            if(x) x--;
            int j=SA[rank[i]-1];
            while(str[i+x]==str[j+x]&&x+i<len&&x+j<len) x++;
            height[rank[i]]=x;
        }
        int ans=0;
        int now=len-1;
        int l=0,r=-1;
        while(now>=0)
        {    
            while(t[l].place-now>=ki-1) l++;
            while(t[r].price>=height[now]&&r>=l) r--;
            t[++r].price=height[now];t[r].place=now; 
            if(len-now+1>=ki) 
            {    
                if(t[l].price>ans) ans=t[l].price;
            }
            now--;        
        }
        printf("%d
    ",ans);
        return 0;
    }

    未经博主同意,不得私自转载!

  • 相关阅读:
    Android开发日志问题
    Android 常用的快捷键(随时更新)
    Android v4 包和v7包问题
    mongoDB 3.0.3 以上GUI 连接认证问题
    python(6)
    python学习(5)
    01_数字滤波器调研
    动态称重数据处理算法及其在禽蛋和类球形水果分选中的应用研究-01
    点云学习
    10-视频图像读取与保存
  • 原文地址:https://www.cnblogs.com/Heey/p/7921816.html
Copyright © 2020-2023  润新知