单调队列与DP
算是一个总结吧!
先来一个模板;
TYVJ 1305 最大子序和
题目描述
输入一个长度为n的整数序列,从中找出一段不超过M的连续子序列,使得整个序列的和最大。
例如 1,-3,5,1,-2,3
当m=4时,S=5+1-2+3=7
当m=2或m=3时,S=5+1=6
输入输出格式
输入格式:
第一行两个数n,m
第二行有n个数,要求在n个数找到最大子序和
输出格式:
一个数,数出他们的最大子序和
输入输出样例
6 4 1 -3 5 1 -2 3
7
数据范围:
100%满足n,m<=300000
这个可以算是单调队列优化dp的模板题了吧;
令f[i]表示以i为结尾的连续子序的最大值;
所以, f[i] = min (sum[i] - sum[j]) ( i - m <= j <= i); sum 为前缀和;
即 f[i] = sum[i] - min(sum[j])( i - m <= j <= i);
显然可以用单调队列维护前缀最小值;
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std; int n, m;
int a[];
int sum[];
deque <int> q;
int ans; int main()
{
cin >> n >> m;
for(register int i = ; i <= n ; i ++)
{
scanf("%d", &a[i]);
sum[i] = sum[i-] + a[i];
} for(register int i = ; i <= n ; i ++)
{
while(!q.empty() && sum[q.front()] > sum[i]) q.pop_front();
q.push_front(i);
while(!q.empty() && i - m > q.back()) q.pop_back();
if(i != )
{
ans = max(ans, sum[i] - sum[q.back()]);
}
else ans = max(ans, sum[i]);
}
cout << ans << endl;
return ; }
zZhBr
再来一道水题;
POJ1821 Fence
Description
Being the team's leader you want to determine for each worker the interval that he should paint, knowing that the total income should be maximal. The total income represents the sum of the workers personal income.
Write a program that determines the total maximal income obtained by the K workers.
Input
Input
N K
L1 P1 S1
L2 P2 S2
...
LK PK SK
Semnification
N -the number of the planks; K ? the number of the workers
Li -the maximal number of planks that can be painted by worker i
Pi -the sum received by worker i for a painted plank
Si -the plank in front of which sits the worker i
Output
Sample Input
8 4
3 2 2
3 2 3
3 3 5
1 1 7
Sample Output
17
Hint
the worker 1 paints the interval [1, 2];
the worker 2 paints the interval [3, 4];
the worker 3 paints the interval [5, 7];
the worker 4 does not paint any plank
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
#define int long long int n, m; struct Par
{
int l, p, s;
}a[]; bool operator < (Par a, Par b)
{
return a.s < b.s;
} int dp[][]; deque <int> q; inline int cacl(int x, int y)
{
return dp[x-][y] - a[x].p * y;
} signed main()
{
while(scanf("%lld%lld", &n, &m) != EOF)
//cin >> n >> m;
{ for(register int i = ; i <= m ; i ++)
{
scanf("%lld%lld%lld", &a[i].l, &a[i].p, &a[i].s);
} sort(a + , a + +m); for(register int i = ; i <= m ; i ++)
{
for(register int k = max((int), a[i].s - a[i].l) ; k <= a[i].s - ; k ++)
{
while(!q.empty() && cacl(i, q.back()) <= cacl(i, k)) q.pop_back();
q.push_back(k);
}
for(register int j = ; j <= n ; j ++)
{
dp[i][j] = max(dp[i-][j], dp[i][j-]);
if(j >= a[i].s)
{
while(!q.empty() && q.front() < j - a[i].l) q.pop_front();
if(!q.empty()) dp[i][j] = max(dp[i][j], cacl(i, q.front()) + a[i].p * j);
}
}
} cout << dp[m][n] << endl; }
return ;
}
zZhBr
来个复杂点的:
SCOI2010 股票交易
提交地址 :股票交易
题目描述
最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律。
通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每个i,都有APi>=BPi),但是每天不能无限制地交易,于是股票交易所规定第i天的一次买入至多只能购买ASi股,一次卖出至多只能卖出BSi股。
另外,股票交易所还制定了两个规定。为了避免大家疯狂交易,股票交易所规定在两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔W天,也就是说如果在第i天发生了交易,那么从第i+1天到第i+W天,均不能发生交易。同时,为了避免垄断,股票交易所还规定在任何时间,一个人的手里的股票数不能超过MaxP。
在第1天之前,lxhgww手里有一大笔钱(可以认为钱的数目无限),但是没有任何股票,当然,T天以后,lxhgww想要赚到最多的钱,聪明的程序员们,你们能帮助他吗?
输入输出格式
输入格式:
输入数据第一行包括3个整数,分别是T,MaxP,W。
接下来T行,第i行代表第i-1天的股票走势,每行4个整数,分别表示APi,BPi,ASi,BSi。
输出格式:
输出数据为一行,包括1个数字,表示lxhgww能赚到的最多的钱数。
输入输出样例
5 2 0
2 1 1 1
2 1 1 1
3 2 1 1
4 3 1 1
5 4 1 1
3
说明
对于30%的数据,0<=W<T<=50,1<=MaxP<=50
对于50%的数据,0<=W<T<=2000,1<=MaxP<=50
对于100%的数据,0<=W<T<=2000,1<=MaxP<=2000
对于所有的数据,1<=BPi<=APi<=1000,1<=ASi,BSi<=MaxP
设dp[i][j]为第i天拥有j个股票的最大收益;
则dp[i] [j] = dp[i-1][j] 这一天不买、卖股票;
dp[i] [j] = max( dp[i-w-1] [k] + bp[i] * ( j - k) ) , 这是卖出股票, 满足j - k <= bs[i] ;
同理:dp[i] [j] = max( dp[i-w-1] [k] -ap[i] * (k - j) ) 这是买入股票, 满足k - j <= as[i];
然后上面两个式子可以用单调队列优化,具体看代码;
//By zZhBr
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
#define maxn 2010
#define int long long int t, p, w; int ap[maxn], bp[maxn], as[maxn], bs[maxn]; int dp[maxn][maxn]; deque <int> q; inline int calc1(int i, int j)
{
return dp[i-w-][j] + bp[i] * j;
} inline int calc2(int i, int j)
{
return dp[i-w-][j] + ap[i] * j;
} signed main()
{
memset(dp, 0xcf, sizeof dp);
cin >> t >> p >> w; for(register int i = ; i <= t ; i ++)
{
scanf("%lld%lld%lld%lld", &ap[i], &bp[i], &as[i], &bs[i]);
} dp[][] = ; for(register int i = ; i <= t ; i ++)
{
for(register int j = ; j <= as[i] ; j ++) dp[i][j] = -ap[i] * j;
for(register int j = p ; j >= ; j --)
{
dp[i][j] = max(dp[i][j], dp[i-][j]);
}
if(i - w - >= )
{
q.clear();
for(register int j = p ; j >= ; j --)
{
if()//卖出
{
while(!q.empty() && calc1(i, q.back()) <= calc1(i, j)) q.pop_back();
q.push_back(j);
while(!q.empty() && - j + q.front() > bs[i]) q.pop_front();
//dp[i][j] = max(dp[i][j], dp[i-w-1][k] + bp[i] * (k - j));
dp[i][j] = max(dp[i][j], calc1(i, q.front()) - bp[i] * j);
}
}
q.clear();
for(register int j = ; j <= p ; j ++)
{
if()//买入
{
while(!q.empty() && calc2(i, q.back()) <= calc2(i, j)) q.pop_back();
q.push_back(j);
while(!q.empty() && j - q.front() > as[i]) q.pop_front();
//dp[i][j] = max(dp[i][j], dp[i-w-1][k] - ap[i] * (j - k));
dp[i][j] = max(dp[i][j], calc2(i, q.front()) - ap[i] * j);
}
} } } int ans = ;
for(register int i = ; i <= p ; i ++)
{
ans = max(ans, dp[t][i]);
}
cout << ans << endl;
return ; }
zZhBr
单调队列与DP的更多相关文章
- 【转】单调队列优化DP
转自 : http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html 单调队列是一种严格单调的队列,可以单调递增,也可以单调递减.队 ...
- 单调队列优化DP,多重背包
单调队列优化DP:http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html 单调队列优化多重背包:http://blog.csdn ...
- bzoj1855: [Scoi2010]股票交易--单调队列优化DP
单调队列优化DP的模板题 不难列出DP方程: 对于买入的情况 由于dp[i][j]=max{dp[i-w-1][k]+k*Ap[i]-j*Ap[i]} AP[i]*j是固定的,在队列中维护dp[i-w ...
- 【HDU 3401 Trade】 单调队列优化dp
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3401 题目大意:现在要你去炒股,给你每天的开盘价值,每股买入价值为ap,卖出价值为bp,每天最多买as ...
- hdu3401:单调队列优化dp
第一个单调队列优化dp 写了半天,最后初始化搞错了还一直wa.. 题目大意: 炒股,总共 t 天,每天可以买入na[i]股,卖出nb[i]股,价钱分别为pa[i]和pb[i],最大同时拥有p股 且一次 ...
- Parade(单调队列优化dp)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2490 Parade Time Limit: 4000/2000 MS (Java/Others) ...
- BZOJ_3831_[Poi2014]Little Bird_单调队列优化DP
BZOJ_3831_[Poi2014]Little Bird_单调队列优化DP Description 有一排n棵树,第i棵树的高度是Di. MHY要从第一棵树到第n棵树去找他的妹子玩. 如果MHY在 ...
- 【单调队列优化dp】 分组
[单调队列优化dp] 分组 >>>>题目 [题目] 给定一行n个非负整数,现在你可以选择其中若干个数,但不能有连续k个数被选择.你的任务是使得选出的数字的和最大 [输入格式] ...
- [小明打联盟][斜率/单调队列 优化dp][背包]
链接:https://ac.nowcoder.com/acm/problem/14553来源:牛客网 题目描述 小明很喜欢打游戏,现在已知一个新英雄即将推出,他同样拥有四个技能,其中三个小技能的释放时 ...
- 单调队列以及单调队列优化DP
单调队列定义: 其实单调队列就是一种队列内的元素有单调性的队列,因为其单调性所以经常会被用来维护区间最值或者降低DP的维数已达到降维来减少空间及时间的目的. 单调队列的一般应用: 1.维护区间最值 2 ...
随机推荐
- 4.1、顺序栈的实现(java实现)
1.实现源码 public class SeqStack { private final int MaxSize = 8; private int top; //栈顶 private Object s ...
- charles 发布Glist
本文参考:charles 发布Glist Publish Gist /发布代码段 选中某个文件,点击Publish Gist,如果你没有github,这个文件将被匿名发布,您也就无法删除它: 当然你可 ...
- Linux 笔记 - 第七章 Vi 和 Vim 编辑器
博客地址:http://www.moonxy.com 一.前言 Vi 与 Vim 都是多模式编辑器,是 Linux 中必不可少的工具.不同的是 Vim 是 Vi 的升级版本,它不仅兼容 Vi 的所有命 ...
- 会计的疑惑--BigDecimal的秘密
为了提供公司的财务信息化,公司A上线了一套自主研发的财务系统,上班第一天,财务C姐就发现了情况不对:几项支出都对,但支出总和一直为0,赶紧向大老板报告.大老板勃然大怒,责令技术部门今天必须解决,小B负 ...
- Android嵌入式开发初学者的几个注意点
一:首先你必须了解ARM平台 Android 移植与驱动核心开发,当然也可以是X86和其他的平台,不过其他平台的Android智能终端开发并不是很多. Android嵌入式智能操作系统是基于Linux ...
- maven的settings.xml详解
<?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://mav ...
- 记一次处理mysql数据库无故锁表的经历
某日,生产环境上的用户表突然无故锁表,原以为只是偶发的bug.所以第一时间想到的解决方案简单粗暴:重启数据库(service mysqld restart).问题得以解决. 10min后,该表再次锁表 ...
- Python-进程相关概念
名词解释: 进程: 一个具有一定独立功能的程序关于某个数据集合的一次运行活动,是系统进行资源分配和调度运行的基本单位 1. 并行 在某个*时间点*,两件或两件以上的事件(任务)同时执行. 比如说,有三 ...
- Python学习笔记整理总结【Django】【MVC/MTV/路由分配系统(URL)/视图函数 (views)/表单交互】
一.Web框架概述 Web框架本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. #!/usr/bin/env python # -*- coding:utf-8 ...
- Apache和Tomcat 配置负载均衡(mod-proxy方式)-无session共享、无粘性session
转:https://blog.csdn.net/wangjunjun2008/article/details/38268483 mod-proxy方式实现负载均衡是利用了Apache 2.x版本自带的 ...