[APIO2009]採油區域(題解)
阿新 • • 發佈:2021-08-22
這是本蒟蒻的第一篇紫題題解
這是一道比較考細節的題目
- 經讀題可知要求一個矩陣三個邊長為 \(k\) 子矩陣的和的最大值值,因為要求子矩陣,所以我們可以採用二維字首和。
- 我們可以發現這個邊長為 \(k\) 的子矩陣分佈只會有 \(6\) 種情況(如下圖)(本人就是因為沒考慮到最後兩種而卡了半天)
- 再靈活使用輔助陣列即可
參考程式碼
#include <bits/stdc++.h> using namespace std; int m, n, k; int a[2005][2005], sum[2005][2005]; int a1[2005][2005], b1[2005][2005], c1[2005][2005], d1[2005][2005], e[2005][2005], f[2005][2005]; int Sum(int x1, int y1, int x2, int y2) { return sum[x2][y2] - sum[x1 - 1][y2] - sum[x2][y1 - 1] + sum[x1 - 1][y1 - 1]; } int main() { cin >> n >> m >> k; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { cin >> a[i][j]; sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j]; } } for (int i = k; i <= n; i++) { for (int j = k; j <= m; j++) { a1[i][j] = max(max(a1[i - 1][j], a1[i][j - 1]), Sum(i - k + 1, j - k + 1, i, j)); } } //左上角最大 for (int i = k; i <= n; i++) { for (int j = m - k + 1; j >= 1; j--) { b1[i][j] = max(max(b1[i - 1][j], b1[i][j + 1]), Sum(i - k + 1, j, i, j + k - 1)); } } //右上角最大 for (int i = n - k + 1; i >= 1; i--) { for (int j = k; j <= m; j++) { c1[i][j] = max(max(c1[i + 1][j], c1[i][j - 1]), Sum(i, j - k + 1, i + k - 1, j)); } } //左下角最大 for (int i = n - k + 1; i >= 1; i--) { for (int j = m - k + 1; j >= 1; j--) { d1[i][j] = max(max(d1[i + 1][j], d1[i][j + 1]), Sum(i, j, i + k - 1, j + k - 1)); } } //右下角最大 for (int i = 1; i <= n - k + 1; i++) { for (int j = 1; j <= m - k + 1; j++) { e[i][i + k - 1] = max(e[i][i + k - 1], Sum(i, j, i + k - 1, j + k - 1)); } } for (int n1 = k + 1; n1 <= n; n1++) { for (int i = 1, j = i + n1 - 1; j <= n; i++, j++) { e[i][j] = max(e[i + 1][j], e[i][j - 1]); } } //第 i ~ j行最大 for (int i = 1; i <= m - k + 1; i++) { for (int j = 1; j <= n - k + 1; j++) { f[i][i + k - 1] = max(f[i][i + k - 1], Sum(j, i, j + k - 1, i + k - 1)); } } for (int n1 = k + 1; n1 <= m; n1++) { for (int i = 1, j = i + n1 - 1; j <= m; i++, j++) { f[i][j] = max(f[i + 1][j], f[i][j - 1]); } } //第 i ~ j列最大 int ans = 0; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { ans = max(ans, e[i + 1][n] + a1[i][j] + b1[i][j + 1]); ans = max(ans, e[1][i] + c1[i + 1][j] + d1[i + 1][j + 1]); ans = max(ans, f[j + 1][m] + a1[i][j] + c1[i + 1][j]); ans = max(ans, f[1][j] + b1[i][j + 1] + d1[i + 1][j + 1]); } } //一橫一豎四種情況 for (int i = 1; i <= n; i++) { for (int j = i + 1; j <= n; j++) { ans = max(ans, e[1][i] + e[i + 1][j] + e[j + 1][n]); } } //兩個橫著 for (int i = 1; i <= m; i++) { for (int j = i + 1; j <= m; j++) { ans = max(ans, f[1][i] + f[i + 1][j] + f[j + 1][m]); } } //兩個豎著 cout << ans; return 0; }