题面来自m大的网站 https://www.malic.xyz/
二维前缀和大家应该都懂吧,然后枚举每一个位置,对这个位置右下方的每一行进行二分,求每一行的第一个列坐标满足这个矩阵内1的个数大于等于k。
时间复杂度n^3log(N),常数比较小。本地测了一下极限数据跑了半秒,应该能过,问了一下xyx大佬,大佬说枚举位置之后可以尺取做,我大概get到了吧哈哈哈,不想写了(其实是不会)
样例过了我就没再测,希望各位大佬能给找找错。
2021.5.25更新:之前的数据还是不够极限,自己造了一组矩阵大小500*500,最后一列全是1的情况,在这组数据下本地跑了2秒,除非Eoj评测机够快,否则是过不去的。还是太菜了。。
#include <bits/stdc++.h>
#define IO \
ios::sync_with_stdio(false);
// cout.tie(0);
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;
LL sum[maxn][maxn];
LL 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
// IO;
// double dur;
// clock_t start, end;
// start = clock();
scanf("%d %d %d %d", &r, &c, &n, &k);
for (int i = 0; i < n; i++)
{
int x, y;
scanf("%d %d", &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];
}
}
LL ans = 0;
for (int i = 1; i <= r; i++)
{
for (int j = 1; j <= c; j++)
{
for (int p = i; p <= r; p++)
{
LL t = check(i, j, p, j);
ans = ans + (t == -1 ? 0 : t);
}
}
}
printf("%lld\n", ans);
// end = clock();
// dur = (double)(end - start);
// printf("Use Time:%f\n", (dur / CLOCKS_PER_SEC));
return 0;
}