main
黄海 2 years ago
parent c57c46e1e3
commit 02a9525caf

@ -0,0 +1,17 @@
#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;
}

@ -1,6 +1,6 @@
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
const int N = 200100;
const int INF = 0x3f3f3f3f;
int n, a[N], s[N], ans[N];

@ -22,6 +22,7 @@
**分析**
先求每个位置的前缀和(某个区间求和前缀和可以说是最快的),然后去找该位置前前缀和的最小值,如果要求一段和最大,就要用这段和减去前面最小的值。
**前缀和解法**
```cpp {.line-numbers}
#include <bits/stdc++.h>
using namespace std;
@ -46,6 +47,27 @@ int main() {
}
```
$DP$ 解法
```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;
}
```
#### [$P1083$ [$NOIP2012$ 提高组] 借教室](https://www.luogu.com.cn/problem/P1083)
#### 暴力
@ -308,37 +330,35 @@ int main() {
}
```
**$O(N^3)$算法**
这道题和$P1115$最大子段和思路类似。
只是将一维升到二维,很重要的解决思路:**矩阵压缩**。
如果能把二维降到一维,那就好处理了。
假设有一个矩阵:
```cpp {.line-numbers}
-5 6 4
1 -2 6
2 1 -3
```
想得到其中任意一个矩阵,我们不妨先确定列。
很明显用两个循环嵌套可以解决。
假设我们取$23$列
```cpp {.line-numbers}
6 4
-1 6
1 -3
```
**$O(N^3)$算法**【选读】
> **引子**
> 给出一段序列,选出其中连续且非空的一段使得这段和最大。第一行是一个正整数$N$,表示了序列的长度。($N<=200000$)
>
这是 <font color='red' size=4><b>$P1115$最大子段和</b></font> 的描述,也就是本题的一维版本。
列取好之后那么每一行的和值就是确定的了
$DP$方程:`dp[i]=max(dp[i-1]+a[i],a[i])` $a[i]$ 表示这个数列的第$i$项。
**注意**:用前缀和可以优化时间。
```cpp {.line-numbers}
10
5
-2
#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;
}
```
接下来我们再在这个一维数组中求最大子序列的和。
就和$P1115$的做法一样了!
**$Code$**

Loading…
Cancel
Save