poj1821 Fence(dp,单调队列优化)
题意:
由k(1 <= K <= 100)个工人组成的团队应油漆围墙,其中包含N(1 <= N <= 16 000)个从左到右从1到N编号的木板。每个工人i(1 <= i <= K)应该坐在木板Si的前面,并且他只能喷涂一个紧凑的间隔(这意味着该间隔中的木板应该是连续的)。此间隔应包含Si木板。同样,工人最多涂li个木板,每涂一块木板他应得到Pi $(1 <= Pi <= 10000)。一块木板最多只能由一个工人涂油漆。所有数字Si应该是不同的。
作为团队的负责人,您要确定每个工人的油漆间隔,但要知道总收入应为最大。总收入是工人个人收入的总和。
题解:
首先按照si从小到达排序
f[i][j]表示前i个工匠粉刷到第j块木板时的最大报酬
如果第i个粉刷工不粉刷墙壁,那么它的最优解dp[i][j]可以由 dp[i-1][j]或者 dp[i][j-1]得到
如果第i个粉刷工需要粉刷墙壁,那么它必须粉刷第si个墙壁
然后我们就需要枚举以si为分界线,第i个工人需要向左边和右边粉刷几个墙壁,那么这就存在一个最优情况
肯定存在一个k满足最优:dp[i][j]=dp[i-1][k]+(j-k)*pi 。我们只需要枚举(j-k)就可以处理掉
“需要向左边和右边粉刷几个墙壁”这个问题(j-Li<=k<=Si-1,j>=Si)
化简一下这个式子就变成了dp[i-1][k]-k*pi+j*pi
其中j*pi是一个常量,哦我们可以先不管它
对于dp[i-1][k]我们可以 维护一个单调递减队列来完成减少每次找dp[i-1][k]最优
其实能用单调队列优化dp的问题很统一,都能化成dp[i]=max/min(f[k])+g[j]的形式,其中f[k]是只和k有关的函数,
g[j]和k无关。
这样的问题由于f[0]-f[j-1]的值可以用单调队列保存,每次更新取出队首元素即可,所以可以省掉一维的枚举.
刚开始复杂度计算错了,开始dfs暴力了,一直TLE。。。。。
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<cstring>
#include<deque>
using namespace std;
const int mod=1e9+7;
const int maxn=1e2+5;
const int N=20000+5;
#define mem(a) memset(a,0,sizeof(a))
int n,k,dp[maxn][N];
deque<int>r;
struct shudui
{
int l,p,s;
} que[maxn];
bool mmp(shudui x,shudui y)
{
return x.s<y.s;
}
//void dfs(int x,int last)
//{
// if(x>k)
// {
// if(dp[k]==16)
// {
// for(int i=1;i<=k;++i)
// printf("%d ",dp[i]);
// printf("\n");
// }
// return;
// }
// int temp=que[x+1].s-last;
// for(int i=1; i<=min(temp,que[x].l); ++i)
// {
// dp[x]=max(dp[x],dp[x-1]+i*que[x].p);
// if(last+i<=que[x].s) dfs(x+1,que[x].s+1);
// else dfs(x+1,last+i);
// }
//}
//void dfs(int x,int last)
//{
// if(x>k)
// {
// if(dp[k]==20)
// {
// for(int i=1;i<=k;++i)
// printf("%d ",dp[i]);
// printf("\n");
// }
// return;
// }
// if(last>que[x].s)
// {
// dp[x]=dp[x-1];
// dfs(x+1,last);
// }
// else
// {
// int temp=(n+1)-last;
// for(int i=1; i<=min(temp,que[x].l); ++i)
// {
// dp[x]=max(dp[x],dp[x-1]+i*que[x].p);
// if(last+i<=que[x].s) dfs(x+1,que[x].s+1);
// else dfs(x+1,last+i);
// }
// }
//
//}
//f[i][j]=Pi*j+max{f[i-1][k]-P[i]*k}
int oper(int i,int k)
{
return dp[i-1][k]-que[i].p*k;
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1; i<=k; ++i)
{
scanf("%d%d%d",&que[i].l,&que[i].p,&que[i].s);
}
sort(que+1,que+1+k,mmp);
//dfs(1,1);
/*
f[i][j]表示前i个工匠粉刷到第j块木板时的最大报酬
如果第i个粉刷工不粉刷墙壁,那么它的最优解dp[i][j]可以由 dp[i-1][j]或者 dp[i][j-1]得到
如果第i个粉刷工需要粉刷墙壁,那么它必须粉刷第si个墙壁
然后我们就需要枚举以si为分界线,第i个工人需要向左边和右边粉刷几个墙壁,那么这就存在一个最优情况
肯定存在一个k满足最优:dp[i][j]=dp[i-1][k]+(j-k)*pi 。我们只需要枚举(j-k)就可以处理掉
“需要向左边和右边粉刷几个墙壁”这个问题(j-Li<=k<=Si-1,j>=Si) 化简一下这个式子就变成了dp[i-1][k]-k*pi+j*pi
其中j*pi是一个常量,哦我们可以先不管它 对于dp[i-1][k]我们可以 维护一个单调递减队列来完成减少每次找dp[i-1][k]最优 其实能用单调队列优化dp的问题很统一,都能化成dp[i]=max/min(f[k])+g[j]的形式,其中f[k]是只和k有关的函数,
g[j]和k无关。
这样的问题由于f[0]-f[j-1]的值可以用单调队列保存,每次更新取出队首元素即可,所以可以省掉一维的枚举.
*/
for(int i=1;i<=k;++i)
{
while(!r.empty()) r.pop_front();
for(int j=max(0,que[i].s-que[i].l);j<que[i].s;++j)
{
while(!r.empty() && oper(i,j)>=oper(i,r.back())) r.pop_back();
r.push_back(j);
}
for(int j=1;j<=n;++j)
{
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
if(j>=que[i].s && j<que[i].s+que[i].l)
{
while(!r.empty() && j-que[i].l>r.front()) r.pop_front();
if(!r.empty()) dp[i][j]=max(dp[i][j],que[i].p*j+oper(i,r.front()));
}
}
}
printf("%d\n",dp[k][n]);
return 0;
}
poj1821 Fence(dp,单调队列优化)的更多相关文章
- [POJ1821]Fence(单调队列优化dp)
[poj1821]Fence 有 N 块木板从左至右排成一行,有 M 个工匠对这些木板进行粉刷,每块木板至多被粉刷一次.第 i 个工匠要么不粉刷,要么粉刷包含木板 Si 的,长度不超过Li 的连续一段 ...
- [poj3017] Cut the Sequence (DP + 单调队列优化 + 平衡树优化)
DP + 单调队列优化 + 平衡树 好题 Description Given an integer sequence { an } of length N, you are to cut the se ...
- 1023: [SHOI2008]cactus仙人掌图(DP+单调队列优化)
这道题吗= =首先解决了我多年以来对仙人掌图的疑问,原来这种高大上的东西原来是这个啊= = 然后,看到这种题,首先必须的就是缩点= = 缩点完之后呢,变成在树上找最长路了= =直接树形dp了 那么那些 ...
- Codeforces 1077F2 Pictures with Kittens (hard version)(DP+单调队列优化)
题目链接:Pictures with Kittens (hard version) 题意:给定n长度的数字序列ai,求从中选出x个满足任意k长度区间都至少有一个被选到的最大和. 题解:数据量5000, ...
- P3084 [USACO13OPEN]照片Photo (dp+单调队列优化)
题目链接:传送门 题目: 题目描述 Farmer John has decided to assemble a panoramic photo of a lineup of his N cows ( ...
- Codeforces 445A Boredom(DP+单调队列优化)
题目链接:http://codeforces.com/problemset/problem/455/A 题目大意:有n个数,每次可以选择删除一个值为x的数,然后值为x-1,x+1的数也都会被删除,你可 ...
- bzoj 1855 dp + 单调队列优化
思路:很容易写出dp方程,很容易看出能用单调队列优化.. #include<bits/stdc++.h> #define LL long long #define fi first #de ...
- 股票交易(DP+单调队列优化)
题目描述 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi, ...
- Luogu 2627 修建草坪 (动态规划Dp + 单调队列优化)
题意: 已知一个序列 { a [ i ] } ,求取出从中若干不大于 KK 的区间,求这些区间和的最大值. 细节: 没有细节???感觉没有??? 分析: 听说有两种方法!!! 好吧实际上是等价的只是看 ...
随机推荐
- SpringBoot入门 简单搭建和使用
前言 差不多两年前,那个时候我准备要做毕业设计了,才第一次知道java有框架这种东西,在网上找了好多SSM的教程,那会儿真的是Spring+SpringMVC+MyBatis搭建的,印象极深的是还要写 ...
- mongodb表索引备份,索引的导出导入
背景 发现有两个mongodb环境的数据库表索引不一致,另一个数据库有索引缺失,需要将一个数据库里的所有表索引导入到另一个数据库 也可用于单独备份数据库所有表的索引 写mongo shell的js脚本 ...
- Ubuntu_Gedit配置
Ubuntu_Gedit配置 为了换Ubuntu的时候能够更加方便,不用再用手重新打一遍代码,丢几个Gedit配置-- External Tools gdb compile (F2) #!/bin/s ...
- FlatBuffers使用小结
最近做一个Android APP,由于离线业务需求,需要在启动APP时候同步大量数据到APP上,遇到了JSON性能瓶颈.从下方的图片中可以看出,当使用 json 传输数据,在解析json的时候会产生大 ...
- ctfhub技能树—web前置技能—http协议—请求方式
打开靶机环境(每次打开都要30金币,好心疼啊) 题目描述为"请求方式" HTTP的请求方式共有八种 1.OPTIONS 返回服务器针对特定资源所支持的HTTP请求方法,也可以利用向 ...
- 此流非彼流——Stream详解
Stream是什么? Java从8开始,不但引入了Lambda表达式,还引入了一个全新的流式API:Stream API.它位于java.util.stream包中. Stream 使用一种类似用 S ...
- 基于循环队列的BFS的原理及实现
文章首发于微信公众号:几何思维 1.故事起源 有一只蚂蚁出去寻找食物,无意中进入了一个迷宫.蚂蚁只能向上.下.左.右4个方向走,迷宫中有墙和水的地方都无法通行.这时蚂蚁犯难了,怎样才能找出到食物的最短 ...
- LVS负载均衡之DR模式原理介绍
LVS基本原理 流程解释: 当用户向负载均衡调度器(Director Server)发起请求,调度器将请求发往至内核空间 PREROUTING 链首先会接收到用户请求,判断目标 IP 确定是本机 IP ...
- 现有以下关系型数据库中的表(见表4-20表4-21和表4-22),要求将具转换为适合Hbase存储的表并插入数据。
① createTable(String tableName, String[] fields) 创建表,参数tableName为表的名称,字符串数组fields为存储记录各个域名称的数组.要 求当H ...
- 。SLI,Service Level Indicator,服务等级指标,其实就是我们选择哪些指标来衡量我们的稳定性。而 SLO,Service Level Objective,服务等级目标,指的就是我们设定的稳定性目标,比如“几个 9”这样的目标。
.SLI,Service Level Indicator,服务等级指标,其实就是我们选择哪些指标来衡量我们的稳定性.而 SLO,Service Level Objective,服务等级目标,指的就是我 ...