2623: 【USACO2013JAN】奶牛排队{ Gold题1}

Memory Limit:128 MB Time Limit:1.000 S
Judge Style:Text Compare Creator:
Submit:2 Solved:3

Description

3. 奶牛排队{ Gold1}

【问题描述】

农夫约翰的N(1 <= N <= 100,000)只奶牛排成了一队,每只牛都用编上了一个“血统编号”,该编号为范围0...1,000,000,000的整数。血统相同的奶牛有相同的编号,也就是可能有多头奶牛是相同的"血统编号"。 
   约翰觉得如果连续排列的一段奶牛有相同的血统编号的话,奶牛们看起来会更具有威猛。为了创造这样的连续段,约翰最多能选出k种血统的奶牛,并把他们全部从队列中赶走。 

请帮助约翰计算这样做能得到的由相同血统编号的牛构成的连续段的长度最大是多少?

【文件输入】

第一行,两个空格间隔的整数N和K 。

接下来N行, 每行一个整数,表示对应奶牛的血统编号。

【文件输出】

    一行,一个整数,表示所能得到的最大连续段的长度

【输入样例】

9 1

2

7

3

7

7

3

7

5

7

【输出样例】

4

【样例说明】

样例说明,只能删除一种奶牛,删除3号血统的奶牛可得到2777757,其中最长的一段连续数字是4个7。

Sample Input Copy

9 1
2
7
3
7
7
3
7
5
7

Sample Output Copy

4

HINT

  原题目其实可以等价为:选择一段区间[i,j],使得区间内至少有k+1中颜色,定义Ai表示这一段区间最多的一种颜色的个数。那么答案显然就是max{Ai}了。

 枚举区间左右端点肯定是不行的,我们只需要枚举左端点,而右端点可以继承上一个右端点的位置,然后往后延展至满足条件的最远处。而取区间内颜色最多的一种,我们只需要用一个堆或者优先队列来动态维护即可。

颜色的编号很多,需要离散化或者hash

 

  进一步思考,维护区间内数量最大的牛的数量需要用到堆或者优先队列。事实上,在最有解所对应的区间,最左端的牛必定是数量最多的牛,所有在枚举左端点时,我们就假定当前左端点的牛的数量为最大值,往右边扫描即可,假设当前满足的区间是[L,R],则考虑L+1为左端点时,右端点直接从R开始考虑。故算法的复杂度可以降到O(N)


Analysis: Cow Lineup by Travis Hance


This problem is equivalent to(等价于) finding, out of all contiguous subintervals(连续子区间) containing at most K+1 distinct(不同的) breed IDs, the maximal number of cows of a single breed contained within such an interval.

The idea is to sweep down the array of cows, keep tracking of the left and right endpoints of an interval. Each time we increment the right endpoint, we may need to increment the left endpoint by some amount so that the interval contains at most K+1 distinct IDs. Of course, when we do this, we will increment the left endpoint as little as possible. To do this, we just need to keep track of (i) for each breed ID, how many cows of that ID are in the interval and (ii) how many distinct breed IDs have a nonzero number of cows in the interval.

Now, when examining any interval(区间), we need to know the maximal number of cows of a single breed in that interval. One approach is to use a data structure such as a set or priority queue to maintain the maximum. Since at most K+1 IDs are nonzero at any given time, this solution takes O(N log(K)) time.

An even simpler approach involves the observation that during this sweep process, at some point the left endpoint will actually be pointing to the correct breed ID, and at this time the interval will contain as many cows of that ID as possible. In other words, rather than asking "Given an interval, what is the maximal number of cows of a single ID within this interval?", we ask "Given a cow, what is the maximum number of cows of that ID which can be in an interval with that cow as the left endpoint?" This solution takes O(N) time.

Here is Mark Gordon's solution in C++:

#include <iostream>

#include <cstdio>

#include <map>

#include <set>

 

using namespace std;

 

int A[100010];

 

int main() {

  freopen("lineup.in", "r", stdin);

  freopen("lineup.out", "w", stdout);

 

  int N, K; cin >> N >> K;

  for(int i = 0; i < N; i++) {

    cin >> A[i];

  }

 

  int res = 0;

  int nz_cnt = 0;

  map<int, int> cnt;

  for(int i = 0, j = 0; i < N; i++) {

    int& ci = cnt[A[i]];

    if(ci == 0) nz_cnt++;

    ci++;

 

    for(; nz_cnt > K + 1; j++) {

      int& cj = cnt[A[j]];

      --cj;

      if(cj == 0) nz_cnt--;

    }

 

    res = max(res, ci);

  }

  cout << res << endl;

 

  return 0;

}