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

    题目描述

    农夫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。

    输入

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

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

    输出

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

    样例输入

    8 2
    1
    2
    3
    2
    3
    2
    3
    1

    样例输出

    4


    题解

    后缀数组+离散化

    题目中m比较大,需要离散化。

    对于这类求重复字串长度的问题,正着做比较难做。

    我们可以先二分答案,然后将问题转化为是否有k次重复的字串。

    假设有k次重复的字串,则一定有连续的k个height大于等于mid。

    那么我们就可以在O(n)的时间内进行judge操作,总时间复杂度为O(nlogn),可以通过。

    另:这里的judge写法比较特殊。由于height[n]是没有值的,所以一般情况下一定能进行下一步判断。但如果m=0,无论如何也无法进行,所以加上特判。

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define N 20005
    int ws[N] , wv[N] , wa[N] , wb[N] , sa[N] , r[N] , n , m , k;
    int rank[N] , height[N];
    struct data
    {
        int num , rn , tnum;
    }a[20001];
    bool cmp1(data a , data b)
    {
        return a.num < b.num;
    }
    bool cmp2(data a , data b)
    {
        return a.rn < b.rn;
    }
    void da()
    {
        int i , j , p , *x = wa , *y = wb , *t;
        for(i = 0 ; i < m ; i ++ ) ws[i] = 0;;
        for(i = 0 ; i < n ; i ++ ) ws[x[i] = r[i]] ++ ;
        for(i = 1 ; i < m ; i ++ ) ws[i] += ws[i - 1];
        for(i = n - 1 ; i >= 0 ; i -- ) sa[--ws[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 >= 0) y[p ++ ] = sa[i] - j;
            for(i = 0 ; i < n ; i ++ ) wv[i] = x[y[i]];
            for(i = 0 ; i < m ; i ++ ) ws[i] = 0;
            for(i = 0 ; i < n ; i ++ ) ws[wv[i]] ++ ;
            for(i = 1 ; i < m ; i ++ ) ws[i] += ws[i - 1];
            for(i = n - 1 ; i >= 0 ; i -- ) sa[--ws[wv[i]]] = y[i];
            for(t = x , x = y , y = t , x[sa[0]] = 0 , i = p = 1 ; i < n ; i ++ )
            {
                if(y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + j] == y[sa[i] + j])
                    x[sa[i]] = p - 1;
                else
                    x[sa[i]] = p ++ ;
            }
        }
        for(i = 1 ; i < n ; i ++ ) rank[sa[i]] = i;
        for(i = p = 0 ; i < n - 1 ; height[rank[i ++ ]] = p)
            for(p ? p -- : 0 , j = sa[rank[i] - 1] ; r[i + p] == r[j + p] ; p ++ );
    }
    bool judge(int m)
    {
        if(m == 0) return 1;
        int i , last = 0;
        for(i = 1 ; i <= n ; i ++ )
        {
            if(height[i] < m)
            {
                if(i - last >= k) return 1;
                last = i;
            }
        }
        return 0;
    }
    int main()
    {
        int i , le , ri , mi , ans = 0;
        scanf("%d%d" , &n , &k);
        for(i = 0 ; i < n ; i ++ )
        {
            scanf("%d" , &a[i].num);
            a[i].rn = i;
        }
        sort(a , a + n , cmp1);
        for(i = 0 ; i < n ; i ++ )
        {
            if(i == 0 || (i > 0 && a[i].num > a[i - 1].num))
                m ++ ;
            a[i].tnum = m;
        }
        sort(a , a + n , cmp2);
        for(i = 0 ; i < n ; i ++ )
            r[i] = a[i].tnum;
        r[n ++ ] = 0;
        m ++ ;
        da();
        le = 0;
        ri = n;
        while(le <= ri)
        {
            mi = (le + ri) >> 1;
            if(judge(mi))
            {
                ans = mi;
                le = mi + 1;
            }
            else ri = mi - 1;
        }
        printf("%d
    " , ans);
        return 0;
    }
  • 相关阅读:
    c++虚函数表 Brew VTBL
    c++ 类数据成员的定义、声明
    变量声明和定义的区别
    C++ 对象间的赋值与拷贝构造函数
    Android应用程序构成
    android平台的技术架构
    认识Service
    Application的作用
    Context的作用
    如何切换到自定义的Activity
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6269533.html
Copyright © 2011-2022 走看看