First, compress all of the x and y coordinates so that everything is in the range [0,N−1].
For each nonempty subset of cows that can be fenced off, consider the rectangle of the minimum size that encloses the subset. This rectangle must contain a cow on each of its four sides. Conversely, each rectangle with a cow on each of its sides corresponds to a unique subset of cows that can be fenced off. Due to the condition that all coordinates are distinct, each side will contain exactly one cow.
A naive approach would be to test whether each of the O(N4) possible rectangles satisfies this condition, giving an O(N5) time solution. For additional an O(N4) time solution, check each rectangle in O(1) time.
For full credit, we need an O(N2) solution. Suppose that we fix the cows a=(xa,ya) and b=(xb,yb) on the bottom and top sides of the rectangle (so ya≤yb). Then the cow c on the left side of the rectangle must satisfy xc≤min(xa,xb) and ya≤yc≤yb. Similarly, the cow d on the right side of the rectangle must satisfy max(xa,xb)≤xd and ya≤yd≤yb. In other words, the number of possibilities for c is the number of points in the rectangle [0,min(xa,xb)]×[ya,yb] while the number of possibilities for d is the number of cows in the rectangle [max(xa,xb),N−1]×[ya,yb]. We can compute these quantities using 2D prefix sums.
Brian Dean's code:
#include <iostream> #include <algorithm> using namespace std; typedef pair<int,int> Point; bool ycomp(Point p, Point q) { return p.second < q.second; } const int MAX_N = 2500; int N, Psum[MAX_N+1][MAX_N+1]; Point P[MAX_N]; int rsum(int x1, int y1, int x2, int y2) { return Psum[x2+1][y2+1] - Psum[x2+1][y1] - Psum[x1][y2+1] + Psum[x1][y1]; } int main(void) { cin >> N; for (int i=0; i<N; i++) { int x, y; cin >> x >> y; P[i] = make_pair(x,y); } sort(P, P+N); for (int i=0; i<N; i++) P[i].first = i+1; sort(P, P+N, ycomp); for (int i=0; i<N; i++) P[i].second = i+1; for (int i=0; i<N; i++) Psum[P[i].first][P[i].second] = 1; for (int i=1; i<=N; i++) for (int j=1; j<=N; j++) Psum[i][j] += Psum[i-1][j] + Psum[i][j-1] - Psum[i-1][j-1]; long long answer = 0; for (int i=0; i<N; i++) for (int j=i; j<N; j++) { int x1 = min(P[i].first, P[j].first) - 1; int x2 = max(P[i].first, P[j].first) - 1; answer += rsum(0,i,x1,j) * rsum(x2,i,N-1,j); } cout << answer + 1 << "\n"; }
Danny Mittal's code:
import java.util.Arrays; import java.util.Comparator; import java.util.Scanner; public class RectangularPasture { static int[][] sums; static int getSum(int fromX, int toX, int fromY, int toY) { return sums[toX][toY] - sums[fromX - 1][toY] - sums[toX][fromY - 1] + sums[fromX - 1][fromY - 1]; } public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); int[] xs = new int[n]; int[] ys = new int[n]; Integer[] cows = new Integer[n]; for (int j = 0; j < n; j++) { xs[j] = in.nextInt(); ys[j] = in.nextInt(); cows[j] = j; } Arrays.sort(cows, Comparator.comparingInt(j -> xs[j])); for (int x = 1; x <= n; x++) { xs[cows[x - 1]] = x; } Arrays.sort(cows, Comparator.comparingInt(j -> ys[j])); for (int y = 1; y <= n; y++) { ys[cows[y - 1]] = y; } sums = new int[n + 1][n + 1]; for (int j = 0; j < n; j++) { sums[xs[j]][ys[j]]++; } for (int x = 0; x <= n; x++) { for (int y = 0; y <= n; y++) { if (x > 0) { sums[x][y] += sums[x - 1][y]; } if (y > 0) { sums[x][y] += sums[x][y - 1]; } if (x > 0 && y > 0) { sums[x][y] -= sums[x - 1][y - 1]; } } } long answer = n + 1; for (int j = 0; j < n; j++) { for (int k = j + 1; k < n; k++) { answer += getSum(Math.min(xs[j], xs[k]), Math.max(xs[j], xs[k]), 1, Math.min(ys[j], ys[k])) * getSum(Math.min(xs[j], xs[k]), Math.max(xs[j], xs[k]), Math.max(ys[j], ys[k]), n); } } System.out.println(answer); } }