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;
}

浙公网安备 33010602011771号