最大m子段和
二维空间不够
前缀模型优化,延迟更新
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]到第
j
j
j个数,组成
i
i
i段时的最大和
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
]
[
j
−
1
]
,
m
a
x
{
d
p
[
i
−
1
]
[
k
−
1
]
}
+
a
[
j
]
(
i
<
=
k
<
=
j
)
)
dp[i][j]=max(dp[i][j-1],max\{dp[i-1][k-1]\}+a[j] \ \ \ \ \ (i<=k<=j))
dp[i][j]=max(dp[i][j−1],max{dp[i−1][k−1]}+a[j] (i<=k<=j))
d
p
[
j
]
=
m
a
x
(
d
p
[
j
−
1
]
,
p
r
e
[
j
−
1
]
)
+
a
[
j
]
dp[j]=max(dp[j-1],pre[j-1])+a[j]
dp[j]=max(dp[j−1],pre[j−1])+a[j]
int tmp;
for(int i = 1 ; i <= m ; i++)//段
{
for(int j = i ; j <= n ; j++)//开始位置
{
tmp=-inf;
for(int k=i-1 ; k <= j-1 ; k++){
tmp=max(tmp , dp[i-1][k]);
}
dp[i][j] = max(dp[i][j-1] , tmp) + a[j];
}
}
cout<< dp[m][n] <<endl;
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<stack>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
const int maxn = 1e6+5;
int dp[maxn] , pre[maxn] , a[maxn];
int n , m;
int main()
{
while(cin >> m >> n)
{
memset(dp,0,sizeof(dp));
memset(pre,0,sizeof(pre));
for(int i = 1 ; i <=n ; i++)
{
scanf("%d" , &a[i]);
}
int tmp;
for(int i = 1 ; i <= m ; i++)//段
{
tmp = -inf;//a[1~n]有负数,为了取每段最大值
for(int j = i ; j <= n ; j++)//开始位置
{
dp[j] = max(dp[j-1],pre[j-1])+a[j];//简化状态转移方程
/*
状态转移方程好理解
主要说下更新次序问题
pre原先是max{dp[i-1][j-1]}j>=i
也就是前i-1段的最大和值
这里涉及一个前缀最大和值如何更新
见第一个写法
它是先循环取最大,再dp更新,dp在后的
多了时间复杂度
这种情况符合前缀模型,所以可以少一层循环减少复杂度
这时dp在前,后面更新pre,再更新tmp结果,每层i循环tmp赋最小值,为了取本轮最大值
注意到下标为j时,使用的是pre[j-1],更新的也是pre[j-1]
分析:本次i层循环,j次循环,先使用pre[j-1],然后更新的pre[j-1],当j+1次时,使用pre[j],但pre[j]并未更新,即每次都是使用前一个,更新前一个
作用:实际上每次i层循环都是使用i-1次循环时更新的pre[j-1]来更新的dp,
可理解为延迟更新一层i循环,达到得到max{dp[i-1][j-1]}j>=i,也就是前i-1段的最大和值
如果pre先于dp更新,当前j次循环时,导致使用了当前i层的值,不符合状态转移方程的含义
如果写成更新pre[j],则当j+1次循环时,要使用pre[j],也导致了使用当前i层的值
最后tmp不断比较当前dp[i][j]最大值,为了下一次j+1次循环更新pre
算是逻辑自洽的解释
以后如果时间复杂度高,如果发现有类似的前缀模型,就可以用这种思想优化
*/
pre[j-1] = tmp;
tmp = max(dp[j] , tmp);
}
}
cout << tmp <<endl;
}
}