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;
}