一类适合初学者的DP:最大子段和与最大子矩阵
最近在水简单DP题,遇到了两道层层递进的DP题,于是记录一下
一、最大子段和
题意:
给出一个长度为n(n<=1e5)的序列,求连续子段的最大值
比如说2 3 -4 5 的最大值是6
而 2 3 -6 7 的最大值为7
样例输入
6
5 4 3 -15 -12 13
样例输出
13
思路一(前缀和)
因为有负数,所以前缀和的值并非单调递增的
而最大字段和只可能出现在任意两个底谷和顶峰之间
图中红色为最大子段和可能出现的地方
所以正序搜出前缀和最小值,倒序搜出最大值,对每个点获得其左边最小的前缀和,右边最大的前缀和,相减即可得到最大子段和。
代码如下:
#include<queue>
#include<string>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lson root<<1
#define rson root<<1|1
using namespace std; long long sum[],a[],n,max1[],min1[]; int main()
{
for(int i=;i<=;i++)
{
sum[i]=-;
}
scanf("%lld",&n);
for(int i=;i<=n;i++)
{
scanf("%lld",&a[i]);
sum[i]=sum[i-]+a[i];
}
long long tmpx=-,tmpn=;
for(int i=;i<=n;i++)
{
tmpn=min(tmpn,sum[i]);
min1[i]=tmpn;
}
for(int i=n;i>=;i--)
{
tmpx=max(tmpx,sum[i]);
max1[i]=tmpx;
}
long long ans=-;
for(int i=;i<=n;i++)
{
ans=max(ans,max1[i]-min1[i-]);
}
printf("%lld\n",ans);
}
思路二(DP)
设f[i]为到i为止以i为终点的最大子段和
则只有两种情况,要么承接以上一个数为终点的子段,要么自己新开一段,既作为开始的起点又作为结束的终点
那么怎么选择呢?这转移方程显然非常好得到:
f[i]=max{f[i-1]+a[i],a[i]}
于是代码如下:
#include<queue>
#include<string>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lson root<<1
#define rson root<<1|1
using namespace std; long long f[],a[],n; int main()
{
f[]=-;
scanf("%lld",&n);
for(int i=;i<=n;i++)
{
scanf("%lld",&a[i]);
}
for(int i=;i<=n;i++)
{
f[i]=max(f[i-]+a[i],a[i]);
}
long long ans=-;
for(int i=;i<=n;i++)
{
ans=max(ans,f[i]);
}
printf("%lld\n",ans);
}
二、最大子矩阵
题意:
给出一个n*m的矩阵(n,m<=200),在矩阵中选出一个子矩阵,使子矩阵的和最大。
样例输入:
4 4
-1 -1 -1 -1
-1 1 1 -1
-1 1 1 -1
-1 -1 -1 -1
样例输出:
4
思路一(n^4暴力)
就是最简单的暴力,统计二维前缀和,枚举左上节点和右下节点,用容斥来算出这个矩阵的和,记录取最大值。
代码懒得打了,反正理论会T。
思路二(n^3降维后跑最大子段和)
枚举一维的所有宽度,将i-j的宽度压缩到一行
对该行跑一遍最大子段和,统计答案
代码写了两种,一种比较好理解但是容易MLE
另一种内存复杂度更优秀一点
第一种:
#include<queue>
#include<string>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lson root<<1
#define rson root<<1|1
using namespace std; long long n,m,map[][],sum[][][],f[][][],ans=-; int main()
{
scanf("%lld%lld",&n,&m);
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
scanf("%lld",&map[i][j]);
}
}
for(int i=;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
for(int k=;k<=m;k++)
{
sum[i][j][k]=sum[i][j-][k]+map[j][k];
}
}
}
for(int i=;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
for(int k=;k<=m;k++)
{
f[i][j][k]=max(f[i][j][k-]+sum[i][j][k],sum[i][j][k]);
ans=max(ans,f[i][j][k]);
}
}
}
printf("%lld\n",ans);
}
第二种:
#include<queue>
#include<string>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lson root<<1
#define rson root<<1|1
using namespace std; long long n,m,ans=-;
long long sum[][],map[][],f[]; int main()
{
scanf("%lld%lld",&n,&m);
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
scanf("%lld",&map[i][j]);
}
}
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
sum[i][j]=sum[i-][j]+map[i][j];
}
}
for(int i=;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
f[]=0ll;
for(int k=;k<=m;k++)
{
f[k]=max(f[k-]+sum[j][k]-sum[i-][k],sum[j][k]-sum[i-][k]);
ans=max(ans,f[k]);
}
}
}
printf("%lld\n",max(ans,0ll));
}
一类适合初学者的DP:最大子段和与最大子矩阵的更多相关文章
- [C#] Timer + Graphics To Get Simple Animation (简单的源码例子,适合初学者)
>_<" 这是一个非常简单的利用C#的窗口工程创立的程序,用来做一个简单的动画,涉及Timer和Graphics,适合初学者,高手略过~
- 推荐10个适合初学者的 HTML5 入门教程
HTML5 作为下一代网站开发技术,无论你是一个 Web 开发人员或者想探索新的平台的游戏开发者,都值得去研究.借助尖端功能,技术和 API,HTML5 允许你创建响应性.创新性.互动性以及令人惊叹的 ...
- 5、WPF实现简单计算器-非常适合初学者练习
Sample Calculator 这是微软社区WPF的一个示例,在源程序的基础上我进行了一点点修改,非常适合初学者练习,详细代码解释. 源程序的下载地址 http://code.msdn.micro ...
- 强烈推荐visual c++ 2012入门经典适合初学者入门
强烈推荐visual c++ 2012入门经典适合初学者入门 此书循序渐进,用其独特.易于理解的教程风格来介绍各个主题,无论是编程新手,还是经验丰富的编程人员,都很容易理解. 此书的目录基本覆盖了Wi ...
- Linux内核开发进阶书籍推荐(不适合初学者)
Linux内核开发进阶书籍推荐(不适合初学者) 很早之前就想写一篇文章总结一下Linux Kernel开发的相关资料,项目的原因,再加上家里的一些事情,一直没能找到闲暇,今天终于有些时间,希望可以完成 ...
- 适合初学者的python实际例子
最近在github上发现了一个有意思的项目,很适合初学者学习python代码. 学习一门语言刚开始的时候是很枯燥的,各种概念语法以及无聊的打印都会让人失去更进一步学习的动力. 很多同学在学习了一段时间 ...
- 7-OKHttp使用详解,步骤挺详细的,适合初学者使用!
OKHttp使用详解,步骤挺详细的,适合初学者使用! 一,OKHttp介绍 okhttp是一个第三方类库,用于android中请求网络. 这是一个开源项目,是安卓端最火热的轻量级框架,由移动支付Squ ...
- 一些适合初学者的C/C++语言开发环境(IDE)
对于很多初学C语言的人来说,第一个开发环境应该都是VC6.0(没办法的事,很多高校都用VC6),在以前VC6确实是比较适合用来进行C/C++的学习. 但现在VC6已经不适合当前的环境了,更不适合新手. ...
- Vue slot-scope的理解(适合初学者)
百度上已经有很多的关于slot-scope的文章,但我感觉都是那些以前没学好,又回头学的人,他们都使用了.Vue文件,我觉得有点不适合初学者,所以我就写一篇适合初学者的. 先抛例程: <!DOC ...
随机推荐
- [转] geochart 地图控件官方示例
<html> <head> <script type='text/javascript' src='https://www.google.com/jsapi'>&l ...
- kali2.0安装及使用笔记(附带vim配置,长期更新)
作者:陈栋权 时间:16/08/19 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明, 且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利. 如有特别用途,请与我联系邮 ...
- 大数据,物联网(Internet of Things),万物互联网(Internet of Everything),云计算,雾计算,边缘计算(Edge Computing) 的区别和联系
大数据是一种规模大到在获取.存储.管理.分析方面大大超出了传统数据库软件工具能力范围的数据集合,具有海量的数据规模.快速的数据流转.多样的数据类型,高价值性和准确性五大特征,即5V(Volume, V ...
- Netty的ChannelHandler,ChannelHandlerContext,ChannelPipeline
本小节一起学习一下ChannelHandler,ChannelHandlerContext,ChannelPipeline这三个Netty常用的组件,不探究它们的底层源码,我们就简单的分析一下用法 首 ...
- leetcode859
class Solution { public: bool buddyStrings(string A, string B) { if (A.length() != B.length()) { ret ...
- IPHONE 64位和32位
参考段一:iPhone 5没有64位的,只有32位架构,苹果是从iPhone 5s开始对全线移动产品使用64位架构.iPhone 5s发布之后的所有产品都是64位的使用LUAJIT或LUAC都可以对L ...
- [iOS]使用autolayout的时候会有明明设置和父视图左右间距为0但却还有空隙问题
有时候设置左右与父视图间距为0但却还有空隙,relative to margin 作怪,到关系里面,把这个取消掉.如关系里面的 firstitem 如果显示 xxView.trailling.marg ...
- hibernate nhibernate sqlserver数据库的默认值冲突解决
数据库中一个字段的默认值设为0,当用hibernate插入数据时,没有对该字段进行操作,结果该字段居然不是0,而是空.后来google了一下,发现应该在.hbm.xml文件中添加一些参数定义(示例中的 ...
- 利用jekyll架设个人博客
jekyll简介 jekyll是一种可以将Markdown或Textile格式文本文件转换成静态网页的工具.利用jekyll编写发布博客的基本过程为: 使用任何一款编辑器编写符合Markdown或Te ...
- java算法 第七届 蓝桥杯B组(题+答案) 8.四平方和
8.四平方和 (程序设计) 四平方和定理,又称为拉格朗日定理:每个正整数都可以表示为至多4个正整数的平方和.如果把0包括进去,就正好可以表示为4个数的平方和. 比如:5 = 0^2 + 0^2 + ...