题目
题目描述
Farmer John 最大的牧草地可以被看作是一个由方格组成的巨大的二维方阵(想象一个巨大的棋盘)。现在,有 N 头奶牛正占据某些方格(1≤N≤2500)。
Farmer John 想要建造一个可以包围一块矩形区域的栅栏;这个矩形必须四边与 x 轴和 y 轴平行,最少包含一个方格。请帮助他求出他可以包围在这样的区域内的不同的奶牛子集的数量。注意空集应当被计算为答案之一。
输入格式
输入的第一行包含一个整数 N。以下 N 行每行包含两个空格分隔的整数,表示一头奶牛所在方格的坐标 (x,y)。所有 x 坐标各不相同,所有 y 坐标各不相同。所有 x 与 y 的值均在 0…10^9 范围内。
输出格式
输出 FJ 可以包围的奶牛的子集数量。可以证明这个数量可以用 64 位有符号整数型存储(例如 C/C++ 中的long long)。
输入输出样例
输入 #1
4
0 2
1 0
2 3
3 5
输出 #1
13
说明/提示
共有 2^4 个子集。FJ 不能建造一个栅栏仅包围奶牛 1、2、4,或仅包围奶牛 2、4,或仅包围奶牛 1、4,所以答案为 2^4−3=16−3=132
测试点 2-3 满足 N≤20。
测试点 4-6 满足 N≤100。
测试点 7-12 满足 N≤500。
测试点 13-20 没有额外限制。
解题思路
我们先把整张地图压缩到n*n,类似8皇后的地图(每行每列只有一个点)。
这里我们用二维的前缀和来维护一块区域内的奶牛数。
无论矩形长什么样,只要围住相同的牛就是一样的,考虑最小的矩形即可
所以矩形的边上一定有一头奶牛。我们先枚举矩形上下两条边,然后看左右两边。假设我们将奶牛a=(xa,ya)和b=(xb,yb)固定在矩形的上下两侧,那么矩形左边的牛c必须满足xc≤min(xa,xb)和ya≤yc≤yb。
换句话说,c的可能数量是矩形内的点的数量[1,min(xa,xb)]×[ya,yb],而d的可能数量是矩形内的奶牛数量[max(xa,xb),n]×[ya,yb]。我们可以用二维前缀和来计算这些量。
参考代码
#include
using namespace std;
typedef long long ll;
const int N = 2505;
int a[N], b[N];
int n;
struct node {
int x, y;
} pos[N];
int sum[N][N];
bool cmp(node x, node y) {
return x.y < y.y;
}
int get(int x1, int y1, int x2, int y2) {
return sum[x2][y2] - sum[x2][y1 - 1] - sum[x1 - 1][y2] + sum[x1 - 1][y1 - 1];
}
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> pos[i].x >> pos[i].y;
a[i] = pos[i].x; b[i] = pos[i].y;
}
sort(a + 1, a + n + 1); sort(b + 1, b + n + 1);
for (int i = 1; i <= n; ++i) {
pos[i].x = lower_bound(a + 1, a + n + 1, pos[i].x) - a;
pos[i].y = lower_bound(b + 1, b + n + 1, pos[i].y) - b;
sum[pos[i].x][pos[i].y] = 1;
}
sort(pos + 1, pos + n + 1, cmp);
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
sum[i][j] += sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
}
}
ll ans = 0;
for (int i = 1; i <= n; ++i) {
for (int j = i; j <= n; ++j) {
int tmp1 = min(pos[i].x, pos[j].x);
int tmp2 = max(pos[i].x, pos[j].x);
ans += get(1, pos[i].y, tmp1, pos[j].y) * get(tmp2, pos[i].y, n, pos[j].y);
}
}
cout << ans + 1 << '\n';
return 0;
}