main
黄海 2 years ago
parent 7f05133d39
commit 474f8b03b4

@ -1,28 +1,29 @@
#include <bits/stdc++.h>
using namespace std;
const int N = 310;
const int N = 330;
int n;
int a[N][N], s[N][N], dp[N];
int res = INT_MIN;
int n, ans;
int main() {
cin >> n;
// 前缀和(竖直方向)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) {
for (int j = 1; j <= n; j++)
cin >> a[i][j];
s[i][j] = s[i - 1][j] + a[i][j]; // 一维前缀和,这可不是二维前缀和
}
// 降维变成一维dp
for (int i = 0; i <= n - 1; i++) // 枚举左上角
for (int j = i + 1; j <= n; j++) // 枚举右下角
for (int k = 1; k <= n; k++) { // 枚举每一列
dp[k] = max(s[j][k] - s[i][k], dp[k - 1] + s[j][k] - s[i][k]);
res = max(res, dp[k]);
for (int j = 1; j <= n; j++)
for (int i = 1; i <= n; i++)
a[i][j] += a[i - 1][j];
for (int i = 1; i <= n; i++) {
for (int k = 1; k <= i; k++) {
for (int j = 1; j <= n; j++) {
int gap = a[i][j] - a[i - k][j];
dp[j] = max(dp[j - 1] + gap, gap);
ans = max(dp[j], ans);
}
// 输出
cout << res << endl;
}
}
cout << ans;
return 0;
}
}

@ -330,34 +330,102 @@ int main() {
```
**$O(N^3)$算法**【选读】
> **引子**
> 给出一段序列,选出其中连续且非空的一段使得这段和最大。第一行是一个正整数$N$,表示了序列的长度。($N<=200000$)
>
这是 <font color='red' size=4><b>$P1115$最大子段和</b></font> 的描述,也就是本题的一维版本。
该题算是$P1115$ 最大子段和的一个升级版,其实思想差不多,都是$DP$,只不过该题需要先进行一个 **矩阵压缩** 即二维变一维。
$DP$方程:`dp[i]=max(dp[i-1]+a[i],a[i])` $a[i]$ 表示这个数列的第$i$项。
**矩阵压缩**
假设有一个矩阵:
```cpp {.line-numbers}
#include<bits/stdc++.h>
using namespace std;
const int N = 200100;
int ans = INT_MIN;
int n;
int a[N] , dp[N];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
dp[i]=max(dp[i-1]+a[i],a[i]);
ans=max(ans,dp[i]);
}
printf("%d\n",ans);
return 0;
}
-5 6 4
1 -2 6
2 1 -3
```
如何对它进行压缩呢,其实不难,类比一下:如果我们把一行看做一个数,这里看做三个数$a,b,c$,那么将这三个相邻数的进行不同的组合,将这个新的组合视为一个新的数,这就是进行压缩处理,例如$a,b,c$可以组合为
$\{[a],[ab],[abc],[b],[bc],[c]\}$,而矩阵压缩也类似。
先设置一个变量$mx$用于保存 **压缩后的一维数组的最大子序列和**。
- **① 第一次我们取第一行**
```cpp {.line-numbers}
-5 6 4
```
则其最大子序列和为$10$$mx=10$。
- **② 第二次取第一二行**
```cpp {.line-numbers}
-5 6 4
1 -2 6
```
注意现在开始是矩阵压缩的 **精髓**,我们将每一列的数进行相加,将多行变为一行。
第一列:$-5+1=-4$
第二列:$6+(-2)=4$
第三列:$4+6=10$
所以压缩后的一维数组为:
```cpp {.line-numbers}
-4 4 10
```
则其最大子序列和为$14$$mx=14$。
- **③ 第三次取第一二三行**
```cpp {.line-numbers}
-5 6 4
1 -2 6
2 1 -3
```
对每一列进行压缩:
第一列:$-5+1+2=-2$
第二列:$6+(-2)+1=5$
第三列:$4+6+(-3)=7$
所以压缩后的一维数组为:
```cpp {.line-numbers}
-2 5 7
```
则其最大子序列和为$12$$mx=14$。
**- ④ 第四次取第二行:**
```cpp {.line-numbers}
1 -2 6
```
则其最大子序列和为$6$$mx=14$。
**- ⑤ 第五次取第二三行:**
```cpp {.line-numbers}
1 -2 6
2 1 -3
```
对每一列进行压缩:
第一列:$1+2=3$
第二列:$-2+1=-1$
第三列:$6+(-3)=3$
所以压缩后的一维数组为:
```cpp {.line-numbers}
3 -1 3
```
则其最大子序列和为$5$$mx=14$。
**- ⑥ 第六次取第三行:**
```cpp {.line-numbers}
2 1 -3
```
则其最大子序列和为$3$$mx=14$。
最后求得这个矩阵最大的子矩阵和为$14$
也就是第一二行的三四列
```cpp {.line-numbers}
6 4
-2 6
```
**$Code$**

Loading…
Cancel
Save