ZR859 坤坤的篮球场 (单调队列)
Description
求一个 n × m n \times m n×m 的网格图中,面积最大的矩形,满足平均值大于 k k k。
1 ≤ n , m ≤ 300 , 1 ≤ a i ≤ 2 × 1 0 5 1 \leq n, m \leq 300, 1 \leq a_i \leq 2 \times 10^5 1≤n,m≤300,1≤ai≤2×105
Solution
将输入的矩阵每个元素减去 k k k ,转换成矩阵之和为正。先预处理二维前缀和。
枚举左右边界的横坐标,并枚举下边界的纵坐标,对于每个 j j j,它对应的最大的上边界坐标为满足 s k < s j s_k < s_j sk<sj 的最小的 k k k。可以发现单调性,所以在从小到大枚举 j j j 的同时维护一个递减单调队列,然后在单调队列找最小的 k k k 即可。
O ( n 3 log n ) O(n^3 \log n) O(n3logn)
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 500 + 5;
int q[N], a[N][N];
ll s[N][N], c[N];
int n, m, k, head, ans, K;
int main() {
scanf("%d%d%d", &n, &m, &K);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
scanf("%d", &a[i][j]);
a[i][j] -= K; s[i][j] = s[i][j - 1] + a[i][j];
}
for (int i = 1; i <= m; i++)
for (int j = i; j <= m; j++) {
head = q[0] = c[0] = 0;
for (int k = 1; k <= n; k++) {
c[k] = c[k - 1] + s[k][j] - s[k][i - 1];
if (c[k] < c[q[head]]) q[++head] = k;
}
for (int k = n; k; k--) {
while (head && c[k] >= c[q[head - 1]]) head--;
ans = max(ans, (k - q[head]) * (j - i + 1));
}
}
printf("%d\n", ans);
return 0;
}

浙公网安备 33010602011771号