VMC 麦田
麦田

题意即要求满足权值和小于等于 \(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;
}
本文来自博客园,作者:Maplisky,转载请注明原文链接:https://www.cnblogs.com/lbh2021/p/18722592

浙公网安备 33010602011771号