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


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

    Time Limit: 5 Sec  Memory Limit: 64 MB
    Submit: 1444  Solved: 784
    [Submit][Status][Discuss]

    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

    HINT

    Source

    【题解】

    蓝书上的SA模板有误!!!!!!!

    求height的时候, while(s[i + k] == s[j + k]) ++ k;一句,

    应写作while(s[i + k] == s[j + k] && i + k < n && j + k < n) ++ k;
    卡了我一下午。。。。。

    据说是SA常用套路,分组+二分

    二分答案x,判断LCP>=x次的字符串是否有k个。不难发现如果有一个height[i]小于x,那么后缀排好序后,所选两个字符串之间不能有i

    (注:查询LCP的heigt是一个左开右闭区间,即查i,jLCP,rank[i] < rank[j],区间为(rank[i], rank[j]])

    于是我们以height[i]小于x的i为分割线,将height分组,每次只能选组内的一个或多个

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cstdlib>
      5 #include <algorithm>
      6 #include <queue>
      7 #include <vector>
      8 #include <cmath> 
      9 #define min(a, b) ((a) < (b) ? (a) : (b))
     10 #define max(a, b) ((a) > (b) ? (a) : (b))
     11 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
     12 template <class T>
     13 inline void swap(T &a, T &b)
     14 {
     15     T tmp = a;a = b;b = tmp;
     16 }
     17 inline void read(int &x)
     18 {
     19     x = 0;char ch = getchar(), c = ch;
     20     while(ch < '0' || ch > '9') c = ch, ch = getchar();
     21     while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
     22     if(c == '-') x = -x;
     23 }
     24 
     25 const int INF = 0x3f3f3f3f;
     26 const int MAXN = 1000000 + 10;
     27 
     28 struct SuffixArray
     29 {
     30     int s[MAXN], sa[MAXN], rank[MAXN], height[MAXN];
     31     int t[MAXN], t2[MAXN], c[MAXN];
     32     int n;
     33     void clear(){n = 0;memset(sa, 0, sizeof(sa));}
     34     
     35     void build_sa(int m)
     36     {
     37         int i, *x = t, *y = t2;
     38         for(i = 0;i < m;++ i) c[i] = 0;
     39         for(i = 0;i < n;++ i) ++ c[x[i] = s[i]];
     40         for(i = 1;i < m;++ i) c[i] += c[i - 1];
     41         for(i = n - 1;i >= 0;-- i) sa[--c[x[i]]] = i;
     42         for(int k = 1;k <= n;k <<= 1)
     43         {
     44             int p = 0;
     45             for(i = n - k;i < n;++ i) y[p ++] = i;
     46             for(i = 0;i < n;++ i) if(sa[i] >= k) y[p ++] = sa[i] - k;
     47             for(i = 0;i < m;++ i) c[i] = 0;
     48             for(i = 0;i < n;++ i) ++ c[x[y[i]]];
     49             for(i = 1;i < m;++ i) c[i] += c[i - 1];
     50             for(i = n - 1;i >= 0;-- i) sa[--c[x[y[i]]]] = y[i];
     51             swap(x, y);
     52             p = 1;x[sa[0]] = 0;
     53             for(i = 1;i < n;++ i) 
     54                 x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p ++;
     55             if(p >= n) break;
     56             m = p;
     57         }
     58     }
     59     
     60     void build_height()
     61     {
     62         int i,j,k = 0;
     63         for(i = 0;i < n;++ i) rank[sa[i]] = i;
     64         for(i = 0;i < n;++ i)
     65         {
     66             if(k) -- k;
     67             j = sa[rank[i] - 1];
     68             while(s[i + k] == s[j + k] && i + k < n && j + k < n) ++ k;
     69             height[rank[i]] = k;            
     70         }
     71     }
     72 }A;
     73 
     74 int k,ma;
     75 
     76 int check(int m)
     77 {
     78     int cnt = 0;
     79     for(int i = 0;i < A.n;++ i)
     80         if(A.height[i] >= m)
     81         {
     82             ++ cnt;
     83             if(cnt + 1 == k) return 1; 
     84         }
     85         else cnt = 0;
     86     return 0;
     87 }
     88 
     89 int main()
     90 {
     91     read(A.n), read(k);
     92     for(int i = 0;i < A.n;++ i)
     93         read(A.s[i]), ma = max(ma, A.s[i]);
     94     A.build_sa(ma + 1);
     95     A.build_height();
     96     int l = 1, r = A.n, mid, ans = 0;
     97     while(l <= r)
     98     {
     99         mid = (l + r) >> 1;
    100         if(check(mid)) ans = mid, l = mid + 1;
    101         else r = mid - 1;
    102     }
    103     printf("%d", ans);
    104     return 0;
    105 }
    BZOJ1717
  • 相关阅读:
    单例 与 static
    ActiveMQ 核心概念
    Jconsole
    死锁
    document write & close
    java.nio.Buffer
    Java 线程控制(输出奇偶数)
    exist & in
    命运
    Super Jumping! Jumping! Jumping!
  • 原文地址:https://www.cnblogs.com/huibixiaoxing/p/8330256.html
Copyright © 2020-2023  润新知