1. 一维 P1115 最大子段和
先从1开始遍历到n
如果我们发现某一段的和是小于0的,就去掉这一段,从下个位置开始枚举
每次新扩大一个窗口就更新一次答案,最后可以枚举到如图
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2e5 + 10;
int a[N];
int main()
{
int MAX = -1e9;
int n;
cin >> n;
for (int i = 0;i < n;i++)
{
cin >> a[i];
MAX = max(a[i], MAX);
}
int res = MAX;
int ans = 0;
for (int i = 0;i < n;i++)
{
ans += a[i];
res = max(ans, res);
if (ans < 0)
ans = 0;
}
cout << res;
}
二维 最大的和
![](https://img-blog.csdnimg.cn/ecdfa459a5704fac988d6f2e6c00139f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAc2Vleg==,size_20,color_FFFFFF,t_70,g_se,x_16)
直接枚举+前缀和的时间复杂度是O(n^4)
为了降低时间复杂度,是否可以套用一维的思想呢
----不妨把扩大一次窗口的个数从一个变成一排,如图所示
定义一个上边界l,下边界r,然后求这段区域内的最大子段和
和一维一样,一直向右扩张,如果有小于0,就把他抛弃
由于一下子要加上一列,所以需要使用前缀和
如图,每次可以多加上一次灰色区域
#include <iostream>
#include <algorithm>
using namespace std;
const int N=100+10;
int a[N][N];
int s[N][N];
int query(int x1,int y1,int x2,int y2)
{
return s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
}
int main()
{
int n;
cin>>n;
int res=-2e9;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>a[i][j];
//前缀和数组
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
s[i][j]=a[i][j]+s[i][j-1]+s[i-1][j]-s[i-1][j-1];
//先枚举上下边界
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
{//再应用一维最大子数组和的性质
int sum=0;
for(int k=1;k<=n;k++)
{
sum+=query(i,k,j,k);
res=max(res,sum);
if(sum<0)
sum=0;
}
}
cout<<res;
}