【PAT 甲级】1007 Maximum Subsequence Sum (25分) (线性DP)

11 篇文章 0 订阅
9 篇文章 0 订阅

1007 Maximum Subsequence Sum (25分)

题目

求序列的最大连续子序列和。序列长度不超过 1e4。

分析

经典 DP 问题,最大子段和。

可以很简单想到令 d p [ i ] dp[i] dp[i] 表示为 0~i 序列的最大子段和,对于每个元素只有三种选择:
① 不加入当前元素
② 加入当前元素,且与前面并一起
③ 加入当前元素,用当前元素重新开始算子段
d p [ i ] = m a x ( d p [ i − 1 ] , d p [ i − 1 ] + a [ i ] , a [ i ] ) dp[i] = max(dp[i-1], dp[i-1]+a[i], a[i]) dp[i]=max(dp[i1],dp[i1]+a[i],a[i])。结果就是 d p [ n ] dp[n] dp[n]

可以看出状态转移比较麻烦,而且不好维护当前最大子段和的头尾。

但如果将 d p [ i ] dp[i] dp[i] 表示为 0~i 序列 a [ i ] a[i] a[i] 结尾的最大子段和,转移方程就变为: d p [ i ] = m a x ( a [ i ] , d p [ i − 1 ] + a [ i ] ) dp[i] = max(a[i], dp[i-1]+a[i]) dp[i]=max(a[i],dp[i1]+a[i]),只需要维和头即可。但是结果变为了所有 d p [ i ] dp[i] dp[i] 的最大值。

#include <bits/stdc++.h>
using namespace std;
#define db(x) cout<<x<<endl

typedef long long ll;
const int INF = 0x3f3f3f;
const int N = 1e5 + 10;
const ll mod = 2147483648;

int n, tmp = 1, a[N]; // tmp 代表当前最大子段和的起点
int dp[N];	// dp[i] 表示以 i 结尾的最大子段和的值,

int main() {
	scanf("%d", &n);
	int maxn = -INF, res_s, res_e;
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
	for (int i = 1, x; i <= n; i++) {
		if (i == 1) dp[i] = a[i];
		if (a[i] >= dp[i - 1] + a[i]) {
			tmp = i; dp[i] = a[i];
		} else {
			dp[i] = dp[i - 1] + a[i];
		}
		if (dp[i] > maxn) {	// 每次更新 maxn
			maxn = dp[i];
			res_s = tmp; res_e = i;
		}
	}
	if (maxn < 0) printf("%d %d %d\n", 0, a[1], a[n]);
	else printf("%d %d %d\n", maxn, a[res_s], a[res_e]);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值