• BZOJ 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次的模式的长度

    题解:

    至少K次可以理解为出现K次,更好满足。

    离散化后求这个串的后缀数组,rank数组及height数组。

    答案应该是height数组中连续K-1个值的最小值的最大值。

    可以用一个单调队列维护。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    //by zrt
    //problem:
    using namespace std;
    int n,K;
    const int MAXN=20005;
    int s[MAXN];
    int sa[MAXN],t[MAXN],t2[MAXN],c[MAXN],rank[MAXN],height[MAXN];
    void build_sa(int m){
        memset(t,-1,sizeof t);
        memset(t2,-1,sizeof t2); 
        int *x=t,*y=t2;
        for(int i=0;i<m;i++) c[i]=0;
        for(int i=0;i<n;i++) c[x[i]=s[i]]++;
        for(int i=1;i<m;i++) c[i]+=c[i-1];
        for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
        for(int k=1;k<=n;k<<=1){
            int p=0;
            for(int i=n-k;i<n;i++) y[p++]=i;
            for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
            for(int i=0;i<m;i++) c[i]=0;
            for(int i=0;i<n;i++) c[x[y[i]]]++;
            for(int i=0;i<m;i++) c[i]+=c[i-1];
            for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
             
            swap(x,y);
            p=1;x[sa[0]]=0;
            for(int i=1;i<n;i++){
                x[sa[i]]= y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
            }
            if(p>=n) break;
            m=p;
        }
    }
     
    int tot;
    struct N{
        int x,w;
        N(int a=0,int b=0){
            x=a,w=b;
        }
    };
    struct dddl{
        N q[MAXN];
        int h,t;
        void insert(N a){
            while(h!=t&&q[t-1].w>=a.w) t--;
            q[t++]=a;
        }
        void pop(int pos){
            if(q[h].x==pos) h++;
        }
        int ask(){
            return q[h].w;
        }
    }dddl;
    int main(){
        #ifdef LOCAL
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
        #endif
        scanf("%d%d",&n,&K);
        for(int i=0;i<n;i++){
            scanf("%d",&s[i]);
            c[i+1]=s[i];
        }
        sort(c+1,c+n+1);
        tot=unique(c+1,c+n+1)-(c+1);
        for(int i=0;i<n;i++){
            s[i]=lower_bound(c+1,c+tot+1,s[i])-c;
        }
        s[n]=-1;
        build_sa(tot+1);
        for(int i=0;i<n;i++) rank[sa[i]]=i;
        int k=0;
        for(int i=0;i<n;i++){
            if(k) k--;
            if(!rank[i]) continue;
            int j=sa[rank[i]-1];
            while(s[i+k]==s[j+k]) k++;
            height[rank[i]]=k;
        }
        int ans=0;
        for(int i=0;i<n;i++){
            dddl.insert(N(i,height[i]));
            dddl.pop(i-K+1);
            ans=max(ans,dddl.ask());
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    MySQL简单实现多字段模糊查询【转】
    PHP检测URL格式是否正确域名地址是否有效【转】
    php如何判断IP为有效IP地址【转】
    PHP isset() 函数使用【转】
    php生成唯一随机码【转】
    php判断一个值是否在数组中【转】
    Win10系统gpedit.msc文件找不到,如何解决【转】
    B
    【金色】种瓜得瓜,种豆得豆 Gym
    J
  • 原文地址:https://www.cnblogs.com/zrts/p/bzoj1717.html
Copyright © 2020-2023  润新知