代码派对
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 512000/512000 K (Java/Others)
Total Submission(s): 78 Accepted Submission(s): 49
Problem Description
比特镇的算法竞赛选手们应邀来到了小Q家中参加盛大的"代码派对"。小Q计划在家中举行一场ACM赛制的联谊赛,3个人为一队进行比赛。
为了让比赛更加有趣,也为了让大家能多多了解他人,小Q在花园的地上画出了一个1000×1000的网格图,从上往下依次编号为第1行到第1000行,从左往右依次编号为第1列到第1000列。小Q让每一名选手选择一个网格图内平行坐标轴的子矩形(x1,y1)−(x2,y2),表示以(x1,y1)和(x2,y2)为对顶点的矩形,包含所有满足x∈[x1,x2]且y∈[y1,y2]的格子。
小Q规定,i,j,k(1≤i<j<k≤n)三人组成一支三人队伍能参赛,当且仅当这三个人选择的子矩形包含至少一个公共格子。请写一个程序,帮助小Q统计有多少种三人组合组成的队伍可以参赛。
第一组样例如下图:
第二组样例如下图:
Input
第一行包含一个正整数T(1≤T≤10),表示测试数据的组数。
每组数据第一行包含一个正整数n(3≤n≤100000),表示选手人数。
接下来n行,每行四个正整数x1,y1,x2,y2(1≤x1≤x2≤1000,1≤y1≤y2≤1000),分别表示每个选手选择的矩形的顶点坐标。
Output
对于每组数据,输出一行一个整数,即满足条件的三人组合数量。
Sample Input
2 3 3 1 3 1 1 1 2 3 2 1 3 2 5 1 1 4 5 2 1 3 2 2 2 3 3 4 5 4 5 1 2 2 4
Sample Output
0 4
Source
解题思路
利用差分和二维前缀和求出每个格子上覆盖的区间数g[i][j]。如果这个时候求C(g[i][j],3)的和,那么会产生很多的重复,因为同样的三个区间可以覆盖多个格子。所以我们只保留覆盖区域左上角的那个格子,因为这个格子一定在区间的上边和左边上,所以最后答案为:总和 - 删掉左边后的和 - 删掉上边后的和 + 删掉上边和左边后的和(前面重复减了这一块,所以加回去)。
代码如下
#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 1005
using namespace std;
typedef long long ll;
int a1[maxn][maxn], a2[maxn][maxn], a3[maxn][maxn], a4[maxn][maxn];
ll c3[100005];
ll work(int a[maxn][maxn])
{
for(int i = 1; i <= 1000; i ++){
for(int j = 1; j <= 1000; j ++)
a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + a[i][j];
}
ll ans = 0;
for(int i = 1; i <= 1000; i ++){
for(int j = 1; j <= 1000; j ++){
ans += c3[a[i][j]];
}
}
return ans;
}
int main()
{
int T;
cin >> T;
c3[3] = 1;
for(int i = 4; i <= 100000; i ++){
c3[i] = (ll)i * (i - 1) * (i - 2) / 6;
}
while(T --){
int n;
cin >> n;
memset(a1, 0, sizeof(a1));
memset(a2, 0, sizeof(a2));
memset(a3, 0, sizeof(a3));
memset(a4, 0, sizeof(a4));
for(int i = 1; i <= n; i ++){
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
a1[x1][y1] ++, a1[x2 + 1][y2 + 1] ++;
a1[x1][y2 + 1] --, a1[x2 + 1][y1] --;
a2[x1 + 1][y1] ++, a2[x2 + 1][y2 + 1] ++;
a2[x1 + 1][y2 + 1] --, a2[x2 + 1][y1] --;
a3[x1][y1 + 1] ++, a3[x2 + 1][y2 + 1] ++;
a3[x1][y2 + 1] --, a3[x2 + 1][y1 + 1] --;
a4[x1 + 1][y1 + 1] ++, a4[x2 + 1][y2 + 1] ++;
a4[x1 + 1][y2 + 1] --, a4[x2 + 1][y1 + 1] --;
}
cout << work(a1) - work(a2) - work(a3) + work(a4) << endl;
}
return 0;
}