2021年ECNU计科考研复试机试 B. 矩形个数(二维前缀和+二分或者尺取)

题面来自m大的网站 https://www.malic.xyz/

2021年ECNU计科考研复试机试 B. 矩形个数(二维前缀和+二分或者尺取)

二维前缀和大家应该都懂吧,然后枚举每一个位置,对这个位置右下方的每一行进行二分,求每一行的第一个列坐标满足这个矩阵内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;
}

 

上一篇:2021牛客暑期多校训练营2(部分补题)


下一篇:ACWING 796. 子矩阵的和