题目背景:

“最大子列和”被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。

本题旨在测试各种不同的算法在各种数据情况下的表现。各组测试数据特点如下:

数据1:与样例等价,测试基本正确性;
数据2:10^2个随机整数;
数据3:10^3个随机整数;
数据4:10^4个随机整数;
数据5:10^5个随机整数;

输入格式:
输入第1行给出正整数K (K≤100000);第2行给出K个整数,其间以空格分隔。

输出格式:
在一行中输出最大子列和。如果序列中所有整数皆为负数,则输出0。

输入样例:
6
-2 11 -4 13 -5 -2
输出样例:
20


思路一 暴力枚举:

通过双重for循环,依次枚举起点与终点,再对该范围内的元素进行求和操作,之后用已经记录好的max值进行比较,再选择是否更新max值。
如果求和使用的是for循环,那么这个算法的渐进复杂度将达到O(n^3 ),我们可以借鉴之前在动态规划是学到的由已知推未知,用一个二维数组来存每次的sum(i,j),这样就可以把渐进复杂度改进为O(n^2).
如果求和使用的是二维数组,在这个二维数组里面仍然存在严重的空间浪费,所以,我们还可以仅借助一个一维数组来求和,而sum(i)表示的是从第一个元素开始到元素i的总和,那么上述的sum(i,j)可表示为sum(j)-sum(i-1) //注意对端点的处理

代码如下:

#include<bits/stdc++.h>
using namespace std;
int N,num[100005],sum[100005];
int main(){scanf("%d",&N);for(int i=1;i<=N;i++)scanf("%d",&num[i]);sum[0] = 0;for(int i = 1; i <= N; i++) {sum[i]=num[i]+sum[i-1];}int ans = num[1]; for(int i = 1; i <= N; i++) {for(int j = i; j <= N; j++) {int s = sum[j] - sum[i - 1];if(s > ans) ans = s;}}printf("%d\n", ans);return 0;
}

思路二 分而治之:

使用分而治之,将一个问题分解为规模更小但类型相同的子问题
对于一个区间,我们一般都是取中点从而分解为两个区间,那么此时我们的问题是应该如何处理这两个区间的关系。
我们可以确定,对于这个区间来说,最终的结果只存在3种可能:
1.目标序列位于左区间
2.目标序列位于右区间
3.目标序列横跨左右区间
对于1,2,我们只需要继续分治即可,问题在于如何处理问题3
对于一个横跨左右区间的序列来说,其实它还是由两段序列所组成:分别以左右区间交界点(即中点)为起点的最大连续子序列,这个问题便被简化为了固定起点的连续序列求和,这两个序列之和即问题3的结果。
这种解法的渐进复杂度为O(n*logn)

代码如下:

#include <bits/stdc++.h>
int N,num[100005];
using namespace std;
int solve(int left, int right){if(left==right)return num[left];int mid=(left+right)/2;int lans=solve(left,mid);int rans=solve(mid+1,right);int sum=0,lmax=num[mid],rmax=num[mid+1];for(int i=mid;i>=left;i--){sum+=num[i];if(sum>lmax)lmax=sum;}sum=0;for(int i=mid+1;i<=right;i++){sum+=num[i];if(sum>rmax)rmax=sum;}int ans=lmax+rmax;if(lans>ans)ans=lans;if(rans>ans)ans=rans;return ans;
}
int main(){scanf("%d",&N);for(int i=1;i<=N;i++)scanf("%d",&num[i]);printf("%d\n",solve(1,N));return 0;
}

思路三 动态规划/在线处理 :

步骤一:确定状态
步骤二:确定状态转移方程
步骤三:确定边界情况和初始条件
步骤四:确定计算顺序

我们用dp[n]表示以第n个数结尾的最大连续子序列的和,于是存在以下递推公式:
dp[n] = max(0, dp[n-1]) + num[n]
对于第n个数,以它为结尾的最大连续子序列可以由前一个数的状态决定,若前者为负数,则会选择0,若为正数,则可相连
这其实不算标准的动态规划,也可认为是一种在线处理每输入一个数据就进行即时处理,在任何一个地方中止输入,算法都能正确给出当前的解
时间复杂度为O(n).

代码如下:

#include<bits/stdc++.h>
int N,num[100005];
using namespace std;
int main(){scanf("%d", &N);for(int i=1;i<=N;i++)scanf("%d",&num[i]);num[0]=0;int ans=num[1];for(int i=1;i<=N;i++){num[i]+=max(0,num[i-1]);if(num[i]>ans)ans=num[i];}printf("%d\n",ans);return 0;
}

思路四 数学分析 (另类在线处理):

对于sum(i,j)来说,求和方法为sum(j)-sum(i-1),那么从数学角度,在确定j的位置时,减去其前方sum(i-1)的最小值即可求以j结尾的最大连续子序列和
那么完全在一次遍历中达到我们的目的,把复杂度保持在O(n)。

#include<bits/stdc++.h>
int N,num[100005];
using namespace std;
int main(){scanf("%d",&N);for(int i=1;i<=N;i++)scanf("%d",&num[i]);int ans=num[1],lmin=0;for(int i=1;i<=N;i++){num[i]+=num[i-1];if(num[i]-lmin>ans)ans=num[i]-lmin;if(num[i]<lmin)lmin=num[i];}printf("%d\n",ans);return 0;
}

结语:

这道题本身是一道经典的题目,同时也是为了下一道题而做的铺垫。

21年寒假第二周周练 蒜厂年会(一)最大连续子序列和相关推荐

  1. 计蒜客 A2232.程序设计:蒜厂年会-单调队列(双端队列(STL deque)实现)滑窗维护最小前缀和...

    程序设计:蒜厂年会 问答问题反馈 只看题面 16.79% 1000ms 262144K 在蒜厂年会上有一个抽奖,在一个环形的桌子上,有 nn 个纸团,每个纸团上写一个数字,表示你可以获得多少蒜币.但是 ...

  2. 计蒜客:蒜厂年会 -java

    在蒜厂年会上有一个抽奖,在一个环形的桌子上,有 nnn 个纸团,每个纸团上写一个数字,表示你可以获得多少蒜币.但是这个游戏比较坑,里面竟然有负数,表示你要支付多少蒜币.因为这些数字都是可见的,所以大家 ...

  3. 2019 蓝桥杯省赛 B 组模拟赛(一)蒜厂年会

    2019 蓝桥杯省赛 B 组模拟赛(一)蒜厂年会 这题有两种情况 1.最大的和是在0~n-1 2.最大的和越过了首尾 这时候只要用n个数的和 - 0~n-1 的连续的最小和 这是求连续子集最大.最小 ...

  4. 【计蒜客 - 蓝桥训练】蒜厂年会(单调队列优化dp,循环数列的最大子段和)

    题干: 在蒜厂年会上有一个抽奖,在一个环形的桌子上,有 nn 个纸团,每个纸团上写一个数字,表示你可以获得多少蒜币.但是这个游戏比较坑,里面竟然有负数,表示你要支付多少蒜币.因为这些数字都是可见的,所 ...

  5. 2019 蓝桥杯省赛 B 组模拟赛(一) J. 程序设计:蒜厂年会 环形连续子序列求和问题

    题目描述 在蒜厂年会上有一个抽奖,在一个环形的桌子上,有 n 个纸团,每个纸团上写一个数字,表示你可以获得多少蒜币.但是这个游戏比较坑,里面竟然有负数,表示你要支付多少蒜币.因为这些数字都是可见的,所 ...

  6. J. 程序设计:蒜厂年会 最大连续和

    在蒜厂年会上有一个抽奖,在一个环形的桌子上,有 nn 个纸团,每个纸团上写一个数字,表示你可以获得多少蒜币.但是这个游戏比较坑,里面竟然有负数,表示你要支付多少蒜币.因为这些数字都是可见的,所以大家都 ...

  7. 计蒜客习题:蒜厂年会

    问题描述 蒜厂要开年会了,所有的员工都要参加. 每两个员工之间都有一个亲密度.在同一个项目工作过的员工之间的亲密度为 1.如果 A 和 B.B 和 C 均在同一个项目中工作过,而 A 和 C 没有,那 ...

  8. 组装一台多媒体计算机必须的部件,计算机基础知识试题8周周周练.doc

    计算机基础知识试题8周周周练.doc (8页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 9.90 积分 城关中学对口升学班"计算机文化基础& ...

  9. 程序员是如何一步一步被诈骗的?《原力计划-打卡挑战》第二周周榜揭晓

    从2月21日开始<原力计划[第二季]>,已经到了第11周,累计32000+名博主参与了本次活动. 本周是<原力计划[第二季]-打卡挑战>第二周,共收到活动投稿 14025 篇原 ...

  10. 7 面阿里,终获 Offer《原力计划【第二季】》第 9周周榜揭晓!!!

    自 2 月 21 日开始<原力计划[第二季]- 学习力挑战>,已经到了第 9 周,累计 28000+ 名博主参与了本次活动. 第 9 周共收到活动投稿 17012 篇原创文章,经过层层筛选 ...

最新文章

  1. windows 2008 引导故障实录
  2. lucene修改索引——(六)
  3. 进制转换(sdut1252)_JAVA
  4. 【Prometheus】存储
  5. 【动态规划】关于转移方程的简单理解
  6. Java获取页面中所有图片的地址
  7. java VM argument_java vm args
  8. 字母框如何影响UI内容的理解
  9. ASP.NET Core Web API 集成测试中使用 Bearer Token
  10. idea连接跳板机_跳板机服务(jumpserver)
  11. 解决连接mysql报错1130
  12. 数据分析领域七大热门职业
  13. 使用localhost访问远程tensorboard
  14. hbuilderx的快捷键整理pdf_47个电脑快捷键大全,让你工作提升100倍,一般人我不告诉他...
  15. indesign教程,如何在帧之间流动文本?
  16. Java8新特性之一:Lambda表达式
  17. 适合mysql的网络存储_mysql 选择合适的存储引擎
  18. 如何免费将excel表格转换成Word文档?
  19. 系统集成考试口诀万金油记忆
  20. 26、backtrader的一些基本概念-市价止损单(stop_order)与限价止损单(stop limit order)的创建和撮合逻辑

热门文章

  1. 调停者模式 java_《JAVA与模式》之调停者模式
  2. Guided Anchoring 论文笔记
  3. 使用海龟绘图,输出四个不同颜色矩形
  4. 微商开始洗牌,怎么样你的团队才能活下来?
  5. 手把手教你做一个网页
  6. python+fastapi+jinja2+mongodb,突然感觉整个人一下就轻松了,python学习之路
  7. 昨夜今晨全球大公司动态
  8. matlab中 .name,matlab中propertyname都有什么
  9. Linux Puppet基础知识
  10. ecshop 添加php标签,ecshop模板调用标签大全