2021年ECNU计科考研复试机试 B. 矩形个数(二维前缀和+二分或者尺取)
作者:互联网
题面来自m大的网站 https://www.malic.xyz/
二维前缀和大家应该都懂吧,然后枚举每一个位置,对这个位置右下方的每一行进行二分,求每一行的第一个列坐标满足这个矩阵内1的个数大于等于k。
时间复杂度n^3log(N),常数比较小。本地测了一下极限数据跑了半秒,应该能过,问了一下xyx大佬,大佬说枚举位置之后可以尺取做,我大概get到了吧哈哈哈,不想写了(其实是不会)
样例过了我就没再测,希望各位大佬能给找找错。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e3 + 10;
const int inf = 0x3f3f3f3f;
int dis[4][2] = {1, 0, 0, 1, 0, -1, -1, 0};
int r, c, n, k;
int sum[maxn][maxn];
int a[maxn][maxn];
int check(int x1, int y1, int p, int L)
{
int R = c;
int x2 = p, y2 = R;
int mid, ans = 0;
if (sum[x2][y2] + sum[x1 - 1][y1 - 1] - sum[x1 - 1][y2] - sum[x2][y1 - 1] < k)
{
return -1;
}
while (L <= R)
{
int mid = (L + R) >> 1;
y2 = mid;
if (sum[x2][y2] + sum[x1 - 1][y1 - 1] - sum[x1 - 1][y2] - sum[x2][y1 - 1] >= k)
{
ans = mid;
R = mid - 1;
}
else
{
L = mid + 1;
}
}
return c - ans + 1;
}
int main()
{
#ifdef WXY
freopen("in.txt", "r", stdin);
#endif
double dur;
// clock_t start, end;
// start = clock();
cin >> r >> c >> n >> k;
for (int i = 0; i < n; i++)
{
int x, y;
cin >> x >> y;
a[x][y] = 1;
}
for (int i = 1; i <= r; i++)
{
for (int j = 1; j <= c; j++)
{
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j];
}
}
long long ans = 0;
for (int i = 1; i <= r; i++)
{
for (int j = 1; j <= c; j++)
{
for (int p = i; p <= r; p++)
{
int t = check(i, j, p, j);
ans = ans + (t == -1 ? 0 : t);
}
}
}
cout << ans << "\n";
// end = clock();
// dur = (double)(end - start);
// printf("Use Time:%f\n", (dur / CLOCKS_PER_SEC));
return 0;
}
标签:计科,x1,int,sum,ECNU,复试,x2,y1,y2 来源: https://blog.csdn.net/qq_44115065/article/details/117086273