diff --git a/TangDou/Topic/PrefixAndSuffix/P1719_1.cpp b/TangDou/Topic/PrefixAndSuffix/P1719_1.cpp index 5f79f3b..e7fc354 100644 --- a/TangDou/Topic/PrefixAndSuffix/P1719_1.cpp +++ b/TangDou/Topic/PrefixAndSuffix/P1719_1.cpp @@ -5,6 +5,7 @@ int n; int a[N][N]; // 存储题目中的矩阵 int s[N][N]; // 二维前缀和 +// O(N^4)算法 int main() { cin >> n; for (int i = 1; i <= n; i++) { diff --git a/TangDou/Topic/PrefixAndSuffix/P1719_2.cpp b/TangDou/Topic/PrefixAndSuffix/P1719_2.cpp index 761b2c1..c21836a 100644 --- a/TangDou/Topic/PrefixAndSuffix/P1719_2.cpp +++ b/TangDou/Topic/PrefixAndSuffix/P1719_2.cpp @@ -1,26 +1,31 @@ #include using namespace std; -const int N = 130; -int a[N][N], s[N][N]; + +const int N = 330; +int n; +int a[N][N], dp[N]; +int res = INT_MIN; + int main() { - int n, res = INT_MIN; cin >> n; - for (int i = 1; i <= n; i++) + // 前缀和(竖直方向) + for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { cin >> a[i][j]; - s[i][j] = s[i - 1][j] + a[i][j]; // 利用一维前缀和,把当前第j列前面的1~j-1列的值,累加和压缩到第j列,每列都是如此处理 + a[i][j] += a[i - 1][j]; } - - // O(N^3)算法 - for (int i = 1; i <= n; i++) { - for (int j = 0; j < i; j++) { // 前缀和需要下标从0开始 - int sum = 0; + } + // 降维变成一维dp + for (int i = 0; i <= n - 1; i++) { + for (int j = i + 1; j <= n; j++) { for (int k = 1; k <= n; k++) { - sum = max(sum, 0) + s[i][k] - s[j][k]; - res = max(res, sum); + dp[k] = max(a[j][k] - a[i][k], dp[k - 1] + a[j][k] - a[i][k]); + res = max(res, dp[k]); } } } - cout << res << endl; + + cout << res; + return 0; } diff --git a/TangDou/Topic/【前缀和与差分】题单.md b/TangDou/Topic/【前缀和与差分】题单.md index 5f0c5b6..5951421 100644 --- a/TangDou/Topic/【前缀和与差分】题单.md +++ b/TangDou/Topic/【前缀和与差分】题单.md @@ -274,7 +274,41 @@ signed main() { #### [$P1719$ 最大加权矩阵](https://www.luogu.com.cn/problem/P1719) -**解题思路** +**$O(N^4)$算法** +```cpp {.line-numbers} +#include +using namespace std; +const int N = 130; +int n; +int a[N][N]; // 存储题目中的矩阵 +int s[N][N]; // 二维前缀和 + +int main() { + cin >> n; + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= n; j++) { + cin >> a[i][j]; + s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j]; + } + } + + int mx = INT_MIN; // 存储答案 + // 遍历左上角坐标,与,右下角坐标 + for (int x1 = 1; x1 <= n; x1++) { + for (int y1 = 1; y1 <= n; y1++) { + for (int x2 = 1; x2 <= n; x2++) + for (int y2 = 1; y2 <= n; y2++) { + if (x2 < x1 || y2 < y1) continue; // 如果左上角比右下角还要大,就不用求了,下一个 + mx = max(mx, s[x2][y2] + s[x1 - 1][y1 - 1] - s[x2][y1 - 1] - s[x1 - 1][y2]); // 求最大值 + } + } + } + cout << mx << endl; // 输出 + return 0; +} +``` + +**$O(N^3)$算法** 这道题和$P1115$最大子段和思路类似。 只是将一维升到二维,很重要的解决思路:**矩阵压缩**。 如果能把二维降到一维,那就好处理了。