【书上讲解】最大m段子段和问题
描述
【题解】
设f[i][j]表示前i个数字分成了j段的最大子段和。
则f[i][j] = max(f[i-1][j]+a[i] (第i个数字和第j段合在一起),f[k][j-1]+a[i] (第i个数字作为第j段的第一个数字,同时在j-1段的情况中找到和最大的那个))
这样的时间复杂度是$O(m*n^2)$的,代码的写法在代码1中
接下来我们做一些优化。
首先把数组的第二维改成滚动数组。
然后令F[i][j]=max(f[1..i][j]);
这样在做第二层的转移的时候f[i][j]就能直接用F[i-1][j-1]做转移了
当然也不用非得再重开一个新的数组。
在f[i][j]做完转移之后把它改成前缀的最大值就行。(注意一定要做完转移之后再改变,因为f[i][j]在转移的时候用到了f[i-1][j])
这样在做转移的时候就少掉了O(N)的一次枚举了
复杂度变成O(n*m)的了.详见代码2
【代码1】
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e6;
const int M = 30;
int f[N+10][M+10],a[N+10];
int n,m;
int main(){
while (~scanf("%d%d",&m,&n)){
for (int i = 1;i <=n;i++) scanf("%d",&a[i]);
for(int l = 1;l <= m;l++){
for (int i = l;i <= n;i++){
if (i==l){
f[i][l] = f[i-1][l-1]+a[i];
}else{
f[i][l] = f[i-1][l]+a[i];//和第l段合并
//printf("%d ",f[i][l]);
//自己独立成段
for (int k = l-1;k <= i-1;k++)
f[i][l] = max(f[i][l],f[k][l-1]+a[i]);
}
}
}
int ans = f[m][m];
for (int i = m+1;i <= n;i++) ans = max(ans,f[i][m]);
printf("%d\n",ans);
}
return 0;
}
【代码2】
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e6;
const int M = 30;
int f[N+10][2],a[N+10];
int n,m;
int main(){
while (~scanf("%d%d",&m,&n)){
for (int i = 1;i <=n;i++) scanf("%d",&a[i]);
memset(f,0,sizeof f);
for(int l = 1;l <= m;l++){
for (int i = l;i <= n;i++){
if (i==l){
f[i][l&1] = f[i-1][(l-1)&1]+a[i];
}else{
f[i][l&1] = f[i-1][l&1]+a[i];//和第l段合并
//printf("%d ",f[i][l]);
//自己独立成段
f[i][l&1] = max(f[i][l&1],f[i-1][(l-1)&1]+a[i]);
}
}
for (int i = l+1;i <= n;i++)
f[i][l&1] = max(f[i][l&1],f[i-1][l&1]);
}
printf("%d\n",f[n][m&1]);
}
return 0;
}
【书上讲解】最大m段子段和问题的更多相关文章
- JAVA理解逻辑程序的书上全部重要的习题
今天随便翻翻看以前学过JAVA理解逻辑程序的书上全部练习,为了一些刚学的学弟学妹,所以呢就把这些作为共享了. 希望对初学的学弟学妹有所帮助! 例子:升级“我行我素购物管理系统”,实现购物结算功能 代码 ...
- 洛谷P1121 环状最大两段子段和
题目描述 给出一段环状序列,即认为A[1]和A[N]是相邻的,选出其中连续不重叠且非空的两段使得这两段和最大. 输入输出格式 输入格式: 输入文件maxsum2.in的第一行是一个正整数N,表示了序列 ...
- 洛谷 P1121 环状最大两段子段和 解题报告
P1121 环状最大两段子段和 题目描述 给出一段环状序列,即认为\(A_1\)和\(A_N\)是相邻的,选出其中连续不重叠且非空的两段使得这两段和最大. 输入输出格式 输入格式: 第一行是一个正整数 ...
- P1121 环状最大两段子段和
P1121 环状最大两段子段和 题目描述 给出一段环状序列,即认为A[1]和A[N]是相邻的,选出其中连续不重叠且非空的两段使得这两段和最大. 输入输出格式 输入格式: 输入文件maxsum2.in的 ...
- 【u124】环状最大两段子段和
Time Limit: 1 second Memory Limit: 128 MB [问题描述] 给出一段环状序列,即认为A[1]和A[N]是相邻的,选出其中连续不重叠且非空的两段使得这两段和最大. ...
- java核心编程书上的一个错误
书上说这段代码说明了java对对象不是采用的按引用调用 这明显错了,java还是引用传递,只是把引用对象的变量复制了,互换了x,y所指的对象,对a,b没有影响
- 最大m段子段和 Day9 - E - Max Sum Plus Plus HDU - 1024
Now I think you have got an AC in Ignatius.L's "Max Sum" problem. To be a brave ACMer, we ...
- c++编程思想(四)--对象和隐藏(感觉书上有误)
c++编程思想里数据抽象和隐藏实现实际就是通常所说的类和封装: 封装,继承,多态对象特点说的很多,就不再说了 关于封装,本人觉得书上有个地方写的有问题,p145和p153都提到Y::f(X*)引用了X ...
- OK 开始实践书上的项目一:即使标记
OK 开始实践书上的项目一:及时标记 然而....又得往前面看啦! ----------------------我是分割线------------------------ 代码改变世界
随机推荐
- iSkysoft iMedia Converter Deluxe for Mac的使用方法
我们电脑上的播放器大多数的播放格式都比较少,所以在播放其它格式的时候容易出错,不能兼容其它的视频格式.今天小编要给大家推荐一种软件,iSkysoft iMedia Converter Deluxe就是 ...
- css实现文本溢出用...显示
文本溢出省略号显示,要实现这个必须 要有四个条件: 1.须有容器宽度:width:value 2.强制文本在一行内显示:white-space:nowrap: 3.溢出内容隐藏:overflow:hi ...
- 存储过程中的in out in out 三种类型的参数
in 是参数的默认模式,这种模式就是在程序运行的时候已经具有值,在程序体中值不会改变. out模式定义的参数只能在过程体内部赋值,表示该参数可以将某个值传递回调用他的过程 in out 表示高参数可以 ...
- PHP面向对象:instanceof 运算符
http://www.nowamagic.net/php/php_InstanceofOperator.php 在PHP5中,通过方法传递变量的类型有不确定性.于是我们很难判断,一些操作是否可以运行. ...
- UNP学习 高级I/O函数
首先为一个I/O函数设置超时,这有三种方法.然后是三个read和write函数的变体: recv和send,他们可以把含有标志的第四个参数从进程传给内核: readv和writev这两个函数可以指定一 ...
- PHP面试 MySQL的SQL语句编写
MySQL的SQL语句编写 面试题一 有A表(id,sex,par,c1,c2),B(id,age,c1,c2)两张表,其中A.id与B.id关联,现在要求写出一条SQL语句,将B中age>50 ...
- 力扣算法题—147Insertion_Sort_List
Sort a linked list using insertion sort. A graphical example of insertion sort. The partial sorted l ...
- Example of dynamic programmatic description
- Suppose there are some itineraries in the Itinerary page, and you want to check on all of them. Se ...
- python中使用动态库
首先,创建一个简单的动态库编程生成dll.so: gcc -fPIC -O2 -shared dll.c -o dll.soC文件:dll.c 如下 #include <stdio.h&g ...
- 学习vim 从常用按键开始
ctrl+e 将屏幕下滚一行 ctrl+u 将屏幕上滚半页 ctrl+d 将屏幕下滚半页 ctrl+b 将屏幕上滚一页 ctrl+f 将屏幕下滚一页 撤销 u 前进 ctrl r 移动 下一个单词 ...