(Analysis by Nick Wu)

In the bronze version of this problem, we naively tried all possible pairs of vertical fences and horizontal fences as long as they were next to a cow. Because the number of cows was low in that problem, we could count the number of cows in each quadrant directly given the arrangement of cows, but that solution will be too slow for the silver version of the problem.

Imagine that we have already fixed the horizontal fence that we are going to place. We can then compute how many cows will be in the upper half and in the lower half. Now, imagine taking a vertical fence and moving it slowly from left to right. Given this, note that most of the cows will stay in the same quadrant, and it is only when the vertical fence moves over a cow that a cow moves from one of the right quadrants to one of the left quadrants.

If we sort the cows by their x-coordinate initially, we can simulate the sweeping of the fence in linear time, which will be fast enough.

Here is my Java code.

import java.io.*;
import java.util.*;
public class balancing {
static State[] list;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("balancing.in"));
PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter("balancing.out")));
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
list = new State[n];
for(int i = 0; i < n; i++) {
st = new StringTokenizer(br.readLine());
list[i] = new State(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken())/2);
}
Arrays.sort(list);
int ret = list.length;
for(int i = 0; i < n; i++) {
ArrayList<State> below = new ArrayList<State>();
ArrayList<State> above = new ArrayList<State>();
for(int j = 0; j < n; j++) {
if(list[j].y <= list[i].y) {
below.add(list[j]);
}
else {
above.add(list[j]);
}
}
int belowIndex = 0;
int aboveIndex = 0;
while(belowIndex < below.size() || aboveIndex < above.size()) {
int xBorder = Integer.MAX_VALUE;
if(belowIndex < below.size()) {
xBorder = Math.min(xBorder, below.get(belowIndex).x);
}
if(aboveIndex < above.size()) {
xBorder = Math.min(xBorder, above.get(aboveIndex).x);
}
while(belowIndex < below.size() && below.get(belowIndex).x == xBorder) {
belowIndex++;
}
while(aboveIndex < above.size() && above.get(aboveIndex).x == xBorder) {
aboveIndex++;
}
ret = Math.min(ret, Math.max(Math.max(belowIndex, below.size() - belowIndex), Math.max(aboveIndex, above.size() - aboveIndex)));
}
}
pw.println(ret);
pw.close();
}

static class State implements Comparable<State> {
public int x,y;

public State(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int compareTo(State s) {
return x - s.x;
}
}

}