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 1n,m300,1ai2×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 
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;
}

你可能感兴趣的:(ZR859 坤坤的篮球场 (单调队列))