VMC 麦田

麦田

image

题意即要求满足权值和小于等于 \(M\) 的矩形个数。

由于求矩形的权值和,必然要二位前缀和处理一下,然后考虑怎么计数。

最简单、暴力的方法肯定是枚举矩形的左上角和右下角,然后查看这中间的权值和。这样就是 \(\mathcal{O(n^4)}\),显然不能通过。

考虑优化,发现如果枚举左上角,再枚举矩形的高,此时矩形的右边界满足单调性。套一个二分,时间复杂度 \(\mathcal{O(n^3logn)}\),还是 T 一个点。

继续深入考虑利用右边界的单调性。发现随着矩形的高逐渐增长,矩形的宽必定单调递减。因此可以优化掉 log,\(\mathcal{O(n^3)}\) 解决问题。

代码如下:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read();
const int N = 505;
int a[N][N];
ll s[N][N];
int main() {
    int n = read(), m = read(), M = read();
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            a[i][j] = read();
            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
            // cerr << s[i][j] << " ";
        }
        // cerr << endl;
    }
    ll ans = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            int l = 1, r = m - j + 1, Mxr = 0;
            while (l <= r) {//这部分也可以不用二分找到初始右端点,直接扫过去即可
                int mid = l + r >> 1;
                s[i][j + mid - 1] + s[i - 1][j - 1] - s[i - 1][j + mid - 1] - s[i][j - 1] <= M ? l = mid + 1, Mxr = mid : r = mid - 1;
            }
            ans += Mxr;
            for (int h = 2; i + h - 1 <= n; ++h) {
                while (Mxr) {
                    ll tmp = s[i + h - 1][j + Mxr - 1] + s[i - 1][j - 1] - s[i - 1][j + Mxr - 1] - s[i + h - 1][j - 1];
                    if (tmp > M)
                        --Mxr;
                    else {
                        ans += Mxr;
                        break;
                    }
                }
            }
        }
    }
    printf("%lld\n", ans);
    return 0;
}
inline int read() {
    int x = 0;
    char c = getchar();
    bool f = 1;
    while (!isdigit(c))
        f = c ^ 45, c = getchar();
    while (isdigit(c))
        x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    return f ? x : -x;
}
posted @ 2025-02-18 18:26  Maplisky  阅读(18)  评论(0)    收藏  举报