地址 https://pintia.cn/problem-sets/994805342720868352/problems/994805514284679168
题目大意
给予一个整数N
下一行再给予N个整数 空格隔开
求上述数字中连续的和最大是多少 并且输出连续最大和的起点和终点的数字 空格隔开
另外如果给予的N个整数都是负数则 连续最大和定义为0 输出N个整数的起点和终点的数字 空格隔开
0 <= N <= 10000
Sample Input: 10 -10 1 2 3 4 -5 -23 3 7 -21 Sample Output: 10 1 4
解答
本题使用动态规划
我们假设和最大的连续子序列的结尾是 num[i]。 那么这个和最大的连续子序列就有两种构成可能
1 num[x],num[x+1]...num[i-1],num[i]的和 num[x],num[x+1]...num[i-1]的和+num[i] 更大 比如 序列 1,2,3, 9,是以9结尾的连续子序列 和为15
2 num[i] num[i]更大 比如 序列 -1,-2,-3, 9 和最大的连续子序列并且以9结尾就是9单个数字
情况1中 1+2+3 又可以认为是 以num[i-1]为结尾 的最大连续子序列的和 ,
如果我们定义dp[i] 是以num[i]为结尾的最大连续子序列的和 那么
上面情况1 2 可以归纳成状态方程 dp[i] = max(dp[i-1]+num[i],num[i])
这样就解决了 求和最大的连续子序列的和的问题。
连续子序列的边界L R的求得如下
因为dp[i] 表示以num[i]结尾的 和最大的连续子序列
那么右边界肯定是R =i , 左边界如果是情况1 则等于dp[i-1]的左边界 如果是情况2 那么L =i
#include <iostream> using namespace std; const int N = 10010; int n; int arr[N]; struct DP{ long long val; int l;int r; }dp[N]; int main() { cin >> n; int allneg = 1; for(int i = 1 ;i <= n ;i++){ cin >> arr[i]; if(arr[i] >= 0) allneg=0; } if(allneg == 1){ cout << 0 << " " << arr[1] << " " << arr[n] << endl; return 0; } dp[0].l = 1; for(int i = 1;i <=n;i++){ dp[i].l = dp[i-1].l; dp[i].val = max(dp[i-1].val+arr[i],(long long) arr[i]); dp[i].r = i; if(dp[i-1].val+arr[i] < arr[i]){ dp[i].l = i; } } struct DP ans = dp[1]; for(int i = 1; i <=n;i++){ if(ans.val < dp[i].val){ ans = dp[i]; } } cout << ans.val << " " << arr[ans.l] <<" " << arr[ans.r] << endl; return 0; }