Thursday, September 18, 2014

USACO \2013\January\Gold\1 - "LINEUP_GOLD"

Farmer John's N cows (1 <= N <= 100,000) are lined up in a row.  Each cow is
identified by an integer "breed ID" in the range 0...1,000,000,000; the
breed ID of the ith cow in the lineup is B(i).  Multiple cows can share the
same breed ID.

FJ thinks that his line of cows will look much more impressive if there is
a large contiguous block of cows that all have the same breed ID.  In order
to create such a block, FJ chooses up to K breed IDs and removes from his
lineup all the cows having those IDs.  Please help FJ figure out
the length of the largest consecutive block of cows with the same breed ID
that he can create by doing this.

PROBLEM NAME: lineup

INPUT FORMAT:

* Line 1: Two space-separated integers: N and K.

* Lines 2..1+N: Line i+1 contains the breed ID B(i).

SAMPLE INPUT (file lineup.in):

9 1
2
7
3
7
7
3
7
5
7

INPUT DETAILS:

There are 9 cows in the lineup, with breed IDs 2, 7, 3, 7, 7, 3, 7, 5, 7. 
FJ would like to remove up to 1 breed ID from this lineup.

OUTPUT FORMAT:

* Line 1: The largest size of a contiguous block of cows with
        identical breed IDs that FJ can create.

SAMPLE OUTPUT (file lineup.out):

4

OUTPUT DETAILS:

By removing all cows with breed ID 3, the lineup reduces to 2, 7, 7, 7, 7,
5, 7.  In this new lineup, there is a contiguous block of 4 cows with the
same breed ID (7).



SOLUTION:

Let's consider solution using sliding window algorithm. 
N <= 1e5, hence complexity of the algorithm should be approximately N*log(N).
At each iteration, we move the right pointer and must maintain the segment satisfying the conditions that there are less or equal K+1 types of ID. If the segment is correct, then we can simply delete the least groups of types in that interval and there will be all the same elements. Otherwise, we move the left pointer.
To do this we need to count the number of types somehow. The first idea is binary tree, right? We may use priority_queue or set, or just map. Let's use map.

So, what we have:

  • We have map<int,int> that can respond how many elements within current interval with some ID.
  • We can figure out is the current segment is correct (if number of types <= K+1)
  • If the segment is correct - try to maximize the answer and keep going increasing right pointer
  • If the segment is not correct - just increment left pointer (move to the right)
The final algorithm looks as follows:
map<int,int> m;
int A[]; // input IDs
...
for (int i = 0, j = 0; i < n; i++)
{
   if (m[A[i]] == 0) types++;
   m[A[i]]++;
   for (; types > k+1; j++)
   {
       m[A[j]]--;
       if (m[A[j]] == 0)
       {
          types--;
       }
   }
   ans = max(ans, m[A[i]]);
}