HDU 1003 Max Sum & Open_OJ NOI 1481 Maximum Sum
HDU 1003 Max Sum
思路 :
- 线性 dp 求最大连续和 , f [ i ] f[i] f[i] 表示 1 ∼ i 1\sim i 1∼i 中最大子段和且子段中包含第 i i i 个元素
- f [ i ] = m a x ( f [ i − 1 ] + a [ i ] , a [ i ] ) f[i]=max(f[i-1]+a[i],a[i]) f[i]=max(f[i−1]+a[i],a[i]) ,划分依据 : 是否将 a [ i ] a[i] a[i] 并入连续子段
一些细节 :
根题题意 : 我们还要求最大子段和的左右端点 ,右端点即为最大值第一次出现的位置 ,左端点预处理一个前缀和来求即可 ,根据题意 ,左端点尽量靠左 。
ac 代码 :
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = a;i <= b;i ++)
typedef long long ll;
typedef double db;
int n;
int const N = 1e5 + 10;
int s[N], w[N], f[N];
void solve(int i){
cin >> n;
for(int i = 1; i <= n; i ++)
cin >> w[i], s[i] = s[i-1] + w[i]; // 预处理
for(int i = 1; i <= n; i ++)
f[i] = max(f[i-1] + w[i], w[i]); // Dp 转移
int res = w[1], l, r = 1;
for(int i = 2; i <= n; i ++) // 求最大值和右端点
if(f[i] > res) res = f[i], r = i;
for(l = 1; l <= r; l ++){ // 求左端点
if(s[r] - s[l-1] == res){
break;
}
}
cout << "Case "<< i << ":\n";
cout << res << ' ' << l << ' ' << r << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
for(int i = 1; i <= T; i ++){
solve(i);
}
return 0;
}
题目链接 Open_OJ NOI 1481 Maximum Sum
思路 :
- 本题与上一题基本类似 ,这题要求两端不相交的最大子段和
- 我们先正着求一遍最大子段和
fl[i]
: 表示 1 ∼ i 1\sim i 1∼i 中以 w [ i ] w[i] w[i] 结尾的最大子段和
同理 ,倒着求一遍最大子段和fr[i]
: 表示 n ∼ i n\sim i n∼i 中以 w [ i ] w[i] w[i] 结尾的最大子段和 - 然后在处理上面两个数组 ,首先使
fl[i]
表示 1 ∼ i 1\sim i 1∼i 中以任意a[1~i]
元素结尾的最大子段和 ,fr[i]
表示 n ∼ i n\sim i n∼i 中以任意元素a[i~n]
结尾的最大子段和 。 - 然后我们枚举两个子段的分界点 ,更新答案即可 。
ac 代码 :
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = a;i <= b;i ++)
typedef long long ll;
typedef double db;
int n;
int const N = 1e5 + 10;
int w[N], fl[N], fr[N];
void solve(){
memset(fl, -0x3f, sizeof fl);
memset(fr, -0x3f, sizeof fr);
cin >> n;
for(int i = 1; i <= n; i ++)
cin >> w[i];
// 第一遍处理
for(int i = 1; i <= n; i ++) fl[i] = max(fl[i-1]+w[i], w[i]);
for(int i = n; i >= 1; i --) fr[i] = max(fr[i+1]+w[i], w[i]);
// 第二遍处理
for(int i = 2; i <= n; i ++) fl[i] = max(fl[i], fl[i-1]);
for(int i = n - 1; i >= 1; i --) fr[i] = max(fr[i], fr[i+1]);
// 更新答案
int res = INT_MIN;
for(int i = 1; i < n; i ++)
res = max(res, fl[i] + fr[i+1]);
cout << res << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
for(int i = 1; i <= T; i ++){
solve();
}
return 0;
}