循环数组最大子段和(动态规划思想的巧妙转换)

个人心得:这是一道好题,线性的最大字段和在动态规划中是司空见惯的。所以对于这种动态规划的思想的巧妙转变也是需要

锻炼的,就像在暑假集训里面碰到的从1到k是递增,k到n是递减的k使得此时的和最大,当时也是毫无办法,虽然后面

想到了分别将首尾展开然后分别求递增的最大和,题目就迎刃而解了。其实这一题题目的分解还是很明白的,

最大值无非就是线性动态规划和横跨俩端的子段,横跨俩端的子段最简单就是俩层循环很明显超时了,后面想着从左边找到最大

的并标志,但是很明显俩段最大值不一定是在一段最大值的前提下,所以后面听取了队友的意见,发现了找出中间的最大负长度子段和。

希望以后能够多开发点思维,让问题变得更简单!

题目:

N个整数组成的循环序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的连续的子段和的最大值(循环序列是指n个数围成一个圈,因此需要考虑a[n-1],a[n],a[1],a[2]这样的序列)。当所给的整数均为负数时和为0。

例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13。和为20。

Input

第1行:整数序列的长度N(2 <= N <= 50000)
第2 - N+1行:N个整数 (-10^9 <= S[i] <= 10^9)

Output

输出循环数组的最大子段和。

Input示例

6
-2
11
-4
13
-5
-2

Output示例

20
 1 #include<iostream>
 2 #include<cstring>
 3 #include<string>
 4 #include<cstdio>
 5 #include<vector>
 6 #include<cmath>
 7 #include<stack>
 8 #include<set>
 9 #include<queue>
10 #include<algorithm>
11 using namespace std;
12 #define in 1000000007
13 int main()
14 {
15     int n;
16     cin>>n;
17     int number[50005];
18     long long sum=0;
19     for(int i=0;i<n;i++)
20         cin>>number[i];
21       long long  maxa=0;
22         long long t=0;
23         long long p=0,q=0;
24     for(int i=0;i<n;i++)
25     {
26         sum+=number[i];
27         t+=number[i];
28         p+=number[i];
29         if(t>0) t=0;
30         if(p<0) p=0;
31         if(p>q) q=p;
32         if(maxa>t) maxa=t;
33     }
34     cout<<max(sum-maxa,q)<<endl;
35     return 0;
36 }
				
时间: 2024-10-18 02:14:10

循环数组最大子段和(动态规划思想的巧妙转换)的相关文章

51nod 1050 循环数组最大子段和【环形DP/最大子段和/正难则反】

1050 循环数组最大子段和 基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题  收藏  关注 N个整数组成的循环序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的连续的子段和的最大值(循环序列是指n个数围成一个圈,因此需要考虑a[n-1],a[n],a[1],a[2]这样的序列).当所给的整数均为负数时和为0. 例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13.和为20. Input 第1

1050 循环数组最大子段和

个整数组成的循环序列a[1],a[2],a[3],-,a[n],求该序列如a[i]+a[i+1]+-+a[j]的连续的子段和的最大值(循环序列是指n个数围成一个圈,因此需要考虑a[n-1],a[n],a[1],a[2]这样的序列).当所给的整数均为负数时和为0. 例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13.和为20. Input 第1行:整数序列的长度N(2 <= N <= 50000) 第2 - N+1行:N个整数 (-10^9 <= S[i] <

51Nod 1050 循环数组最大子段和 | DP

Input示例 6 -2 11 -4 13 -5 -2 Output示例 20 分析: 有两种可能,第一种为正常从[1 - n]序列中的最大子字段和:第二种为数组的total_sum - ([1-n]序列中的最短序列和) 最后结果为 max { 第一种, 第二种}. 对于第二种: 循环数组求最大子段和,可能出现中间的一部分不要,要两边的数.比如:-1 4 -1 -5 5 -2 1 -1 3,他的最大子段和就为 左边的-1 4加上右边的5 -2 1 -1 3,也就是,去掉1 -5这一段后的结果.而

[51NOD1959]循环数组最大子段和(dp,思路)

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1050 这道题的最大子段和有两种可能,一种是常规的子段和,另一种是从结尾到开头的一个子段.常规做是一种可能,另一种带循环的则可以认为是序列中间有一段最小子段和,把这段最小子段和去掉,剩下的可能就是最大子段和了. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL;

51Nod1050 循环数组最大子段和

Problem N个整数组成的循环序列a[1],a[2],a[3],-,a[n],求该序列如a[i]+a[i+1]+-+a[j]的连续的子段和的最大值(循环序列是指n个数围成一个圈,因此需要考虑a[n-1],a[n],a[1],a[2]这样的序列).当所给的整数均为负数时和为0. 例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13.和为20. Solution 最大字段和最大,或者去掉中间某个最小字段和剩下的最大. Code #include<stdio.h> #inc

51nod 1050 循环数组最大子段和

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1050 题意: 思路: 情况无非分为两种: ①正常的最大子段和. ②首尾相连的最大子段和,此时中间的那段肯定是最小子段和,用总的sum-最小子段和即可. 最后比较两者大小. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio>

循环数组最大子段和

记得以前好像做过,应该是学长给了个思路才想出来的,明明是一道水题,写了半天全是错的,给自己留个纪念吧,思路很简单:把数组复制一遍接到数组后面,先求最大值 ,要是直接求的话肯定错,个数要限制一下,给个例子:4 5 6 7 ,复制之后是 4 5 6 7 4 5  6 7 要是没有个数限制的话就全加上了,之后这个先来一个候选值,因为不一定对 例子是: 1 2 3  -5 3  2 1,自己跑一遍的话可以知道是3 + 2 + 1 + 1 + 2 + 3之前写的会全加上,这个就要另一个思路了,就是反其道而

51nod 1050 循环数组最大子段和 (dp)

http://www.51nod.com/onlineJudge/questionCode.html#problemId=1050&noticeId=13385 参考:http://blog.csdn.net/acdreamers/article/details/38760805 #include<cstdio> #include<algorithm> using namespace std; typedef long long ll; int n; ll a[100001

区间型动态规划的记忆化搜索实现与环形动态规划的循环数组实现

区间型动态规划的典型例题是石子归并,同时使用记忆化搜索实现区间动归是一种比较容易实现的方式,避免了循环数组实现的时候一些边界的判断 n堆石子排列成一条线,我们可以将相邻的两堆石子进行合并,合并之后需要消耗的代价为这两堆石子的质量之和,问最小的合并代价 状态转移方程很容易给出: f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[i][j]) 因为要计算区间和,考虑前缀和进行预处理 然后我们给出用记忆化搜索形式实现的代码,这里的记忆化搜索形式可以作为后续问题的一个模