动态规划 最大子序列

1479. 最大子序列和

给定一个包含 K 个整数的序列 {N1,N2,…,NK}。

连续子序列定义为 {Ni,Ni+1,…,Nj},其中 1≤i≤j≤K。

最大子序列是指序列内各元素之和最大的连续子序列。

例如,给定序列 {−2,11,−4,13,−5,−2},它的最大子序列为 {11,−4,13},其各元素之和为 20。

现在你需要求出最大子序列的各元素之和,并且输出最大子序列的第一个元素和最后一个元素的值。

输入格式
第一行包含一个整数 K。

第二行包含 K 个整数。

输出格式
输出一行三个整数,分别表示最大子序列的各元素之和以及最大子序列的第一个元素和最后一个元素的值。

设最大子序列为 {Ni,Ni+1,…,Nj},如果答案不唯一,则选择 i 更小的解,如果仍不唯一,则选择 j 更小的解。

注意,我们规定,如果所有 K 个数字均为负数,则其最大和定义为 0,并且应该输出整个序列的第一个数字和最后一个数字。

数据范围
1≤K≤10000,
序列内元素的绝对值不超过 105。

输入样例:
10
-10 1 2 3 4 -5 -23 3 7 -21
输出样例:
10 1 4

算法思路

这道题是明显的使用动态规划去解决的题目,这道题的要点是找到其中的状态转移方程我们考虑以i为首的子序列的最大值,以及以j为底的子序列的最大值。我们首先考虑其中的状态转移,先考虑以i为首的,先给最后一个元素赋值,然后从后往前递推。在这里插入图片描述
考虑以j为底的子序列同理,不过是从前往后递推的。
在这里插入图片描述
动态规划问题最大的特点是他从大问题划分成子问题的时候,存在公共子问题,而分治法的子问题是不重叠的。

代码

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;


	
int main(){

	int k;
	int f[100010];
	int dp[100010];
	int dpx[100010];
	int ma=-999999;
	int mi=-999999;
	int x,y;
	int res=0;
	
	cin>>k; 
	for(int i=0;i<k;i++){
		cin>>f[i];
	}
	
	dp[0]=f[0];
	dpx[k-1]=f[k-1];
	
	
	for(int i=1;i<k;i++){
		dp[i]=max(f[i],dp[i-1]+f[i]);
	}
	
	for(int i=k-2;i>=0;i--){
		dpx[i]=max(f[i],dpx[i+1]+f[i]);
	}

	for(int i=k-1;i>=0;i--){
		if(dp[i]>=ma){
			ma=dp[i];
			x=i;
		}
		if(dpx[i]>=mi) {
			mi=dpx[i];
			y=i;
		}
	}
	
	for(int i=0;i<k;i++){
	    if(f[i]<0) res++;
	}
	
	if(res==k){
	    cout<<0<<" "<<f[0]<<" "<<f[k-1]<<endl;
	}else{
	    cout<<ma<<" "<<f[y]<<" "<<f[x]<<endl;
	}
	
	return 0;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值