3.13 组队训练 补题记录

队伍:新建文本文档

来源:2020-2021 ICPC - Gran Premio de Mexico - Repechaje - I. Integers Rectangle Challenge

题意

给定 \(N\times M\) 矩阵,第 \(i\) 行第 \(j\) 列的数为 \(R_{i,j}\) 。选出三个不重叠的子矩形,使选中的权值和最大。

解法

\((a, b, c, d)\) 表示子矩形 \(\{ (x, y): a \le x \le c, b \le y \le d \}\)

如果只有一个,就是经典的最大子矩形问题,预处理每个子矩形 \((a, b, c, d)\) 的“最大子矩形”,记为 \(f(a, b, c, d)\)

如果是两个不重叠的子矩形可以怎么做?

考虑两个矩形的分隔线。假设答案的两个矩形分别在 \((1, 1, i, m)\)\((i + 1, 1, n, m)\) 内。于是枚举 \(i\) ,用之前预处理的 \(f\) 可以很轻松得到转移:\(ans = \max\{f(1, 1, i, m) + f(i + 1, 1, n, m) \}\) 。同样我们可以枚举列作为分隔线。

回到问题,三个呢?

枚举两条分隔线。但我们发现可能有类似“品”字的结构,额外统计此类情况(经旋转,共四种)计算即可。

代码

#include <bits/stdc++.h>

using namespace std;

#define dd(x) cout<<#x<<" = "<<x<<" " 
#define de(x) cout<<#x<<" = "<<x<<"\n" 
#define mem(p, w) memset(p, w, sizeof(p))
#define mkp make_pair
#define se second
#define fi first

typedef long long ll;
typedef double db;
typedef long double ldb;
typedef pair<int, int> pii;

const int inf = 0x3f3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;

int A[55][55], sum[55][55];
bool vis[55][55][55][55];
int F[55][55][55][55];
int calc(int a, int b, int c, int d) {
    return sum[c][d] - sum[a - 1][d] - sum[c][b - 1] + sum[a - 1][b - 1];
}

int dfs(int a, int b, int c, int d) {
    int &ret = F[a][b][c][d];
    if(a == c && b == d) return ret = A[a][b];
    if(vis[a][b][c][d]) return ret;
    vis[a][b][c][d] = 1;
    ret = calc(a, b, c, d);
    for(int i = a; i < c; ++i)
        ret = max(ret, max(dfs(a, b, i, d), dfs(i + 1, b, c, d)));
    for(int i = b; i < d; ++i)
        ret = max(ret, max(dfs(a, b, c, i), dfs(a, i + 1, c, d)));
    return ret;
}
int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j)
            scanf("%d", &A[i][j]);
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j)
            sum[i][j] = A[i][j] + sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
    dfs(1, 1, n, m);
    int ans = -inf;
    // 三行
    for(int i = 1; i < n; ++i)
        for(int j = i + 1; j < n; ++j)
            ans = max(ans, F[1][1][i][m] + F[i + 1][1][j][m] + F[j + 1][1][n][m]);
    // 三列
    for(int i = 1; i < m; ++i)
        for(int j = i + 1; j < m; ++j)
            ans = max(ans, F[1][1][n][i] + F[1][i + 1][n][j] + F[1][j + 1][n][m]);
    // 品
    for(int i = 1; i < n; ++i)
        for(int j = 1; j < m; ++j) {
            ans = max(ans, F[1][1][i][j] + F[1][j + 1][i][m] + F[i + 1][1][n][m]);
            ans = max(ans, F[1][1][n][j] + F[1][j + 1][i][m] + F[i + 1][j + 1][n][m]);
            ans = max(ans, F[1][1][i][m] + F[i + 1][1][n][j] + F[i + 1][j + 1][n][m]);
            ans = max(ans, F[1][1][i][j] + F[i + 1][1][n][j] + F[1][j + 1][n][m]);
        }
    printf("%d\n", ans);
    return 0;
}
posted @ 2021-03-16 21:19  Dayu2001  阅读(248)  评论(0)    收藏  举报