zoukankan      html  css  js  c++  java
  • 【BZOJ1717】[Usaco2006 Dec]Milk Patterns 产奶的模式 后缀数组

    【BZOJ1717】[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

    题解:论文中的例题。

    由于数的范围比较大,直接上基数排序会炸,所以本题可以用快排来搞,(但是我没写出来快排233),好吧于是我就先离散化,然后再用基数排序做的。

    先二分答案,将height分成长度不小于ans的若干组,如果某一组的后缀个数不小于k,那么存在满足条件的长度为ans的子串。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int maxn=20010;
    int n,m,K;
    int ra[maxn],rb[maxn],r[maxn],sa[maxn],st[maxn],rank[maxn],h[maxn];
    struct node
    {
        int num,org;
    }v[maxn];
    bool cmp(node a,node b)
    {
        return a.num<b.num;
    }
    int readin()
    {
        int ret=0;    char gc;
        while(gc<'0'||gc>'9')    gc=getchar();
        while(gc>='0'&&gc<='9')    ret=ret*10+gc-'0',gc=getchar();
        return ret;
    }
    void work()
    {
        int i,j,k,p,*x=ra,*y=rb;
        for(i=0;i<n;i++)    st[x[i]=r[i]]++;
        for(i=1;i<m;i++)    st[i]+=st[i-1];
        for(i=n-1;i>=0;i--)    sa[--st[x[i]]]=i;
        for(j=p=1;p<n;j<<=1,m=p)
        {
            for(p=0,i=n-j;i<n;i++)    y[p++]=i;
            for(i=0;i<n;i++)    if(sa[i]>=j)    y[p++]=sa[i]-j;
            for(i=0;i<m;i++)    st[i]=0;
            for(i=0;i<n;i++)    st[x[y[i]]]++;
            for(i=1;i<m;i++)    st[i]+=st[i-1];
            for(i=n-1;i>=0;i--)    sa[--st[x[y[i]]]]=y[i];
            for(swap(x,y),p=1,i=1,x[sa[0]]=0;i<n;i++)
                x[sa[i]]=(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j])?p-1:p++;
        }
        for(i=1;i<n;i++)    rank[sa[i]]=i;
        for(i=k=0;i<n-1;h[rank[i++]]=k)
            for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
    }
    int solve(int sta)
    {
        int i,tot=1;
        for(i=1;i<n;i++)
        {
            if(h[i]<sta)    tot=0;
            if(++tot>=K)    return 1;
        }
        return 0;
    }
    int main()
    {
        n=readin(),K=readin();
        int i;
        for(i=0;i<n;i++)    v[i].num=readin(),v[i].org=i;
        sort(v,v+n,cmp);
        int pre=-1,now=0;
        for(i=0;i<n;i++)
        {
            if(v[i].num>pre)    pre=v[i].num,now++;
            r[v[i].org]=now;
        }
        r[n++]=0;
        m=n;
        work();
        int L=1,R=n-1,mid;
        while(L<R)
        {
            mid=L+R>>1;
            if(solve(mid))    L=mid+1;
            else    R=mid;
        }
        printf("%d",L-1);
        return 0;
    }
  • 相关阅读:
    对象内存布局 (2)
    对象内存布局 (1)
    C++虚函数及虚函数表解析
    C++ inline 函数
    第十六章 贪心算法——0/1背包问题
    动态规划——活动选择问题
    第十六章 贪心算法——活动选择问题
    第十五章 动态规划——最优二叉搜索树
    Cannot load supported formats: Cannot run program "svn"
    idea 配置多个tomcat
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6269530.html
Copyright © 2011-2022 走看看