[POJ1821]Fence(单调队列优化dp)
[poj1821]Fence
有 N 块木板从左至右排成一行,有 M 个工匠对这些木板进行粉刷,每块木板至多被粉刷一次。第 i 个工匠要么不粉刷,要么粉刷包含木板 Si 的,长度不超过Li 的连续一段木板,每粉刷一块木板可以得到 Pi 的报酬。求如何安排能使工匠们获得的总报酬最多。
1<=N<=16000,1<=M<=100
输入
NK
L1 P1 S1
L2 P2 S2
...
LK PK SK
输出
输出包含一个整数,即最大总收入。
样例输入:
8 4
3 2 2
3 2 3
3 3 5
1 1 7
样例输出:
17
先把所有工匠按照\(Si\)排序,这样一来,每个工匠粉刷的木板一定在上一个工匠之后,使我们能够按顺序进行线性 DP。
设\(F[i,j]\)表示安排前\(i\)个工匠粉刷前\(j\)块木板(可以有空着不刷的木板),工匠能获得的最多报酬。
1.第\(i\)个工匠可以什么也不刷,此时\(F[i,j]=F[i-1,j]\)。
2.第\(j\)块木板可以空着不刷,此时\(F[i,j]=F[i,j-1]\)。
3.第\(i\)个工匠粉刷第\(k+1\)块到第\(j\)块木板。根据题意,该工匠粉刷总数不能超过\(Si\),所以需要满足: \(k+1<=Si<=j\)并且\(j-k<=Li\)。于是,有状态转移方程:
\]
我们重点来看这个方程怎么优化。首先,在考虑内层循环\(j\)以及决策\(k\)时,可把外层循环变量\(i\)看作定值。这样一来,状态转移方程中的各项可分为两部分:
1.\(Pi*j\),除定值\(i\)外,只有状态变量\(j\)。
2.\(F[i-1,k]-Pi*k\),除定值\(i\)外,只有决策变量\(k\)。状态转移方程可写为:
\]
当 \(j\) 增大时,\(k\) 的取值范围上界 \(Si-1\) 不变,下界 \(j-Li\) 变大。这时
我们来比较任意两个决策 \(k1\) 和 \(k2\)。不妨设 \(k1<k2<=Si-1\)。因为 \(k2\) 比 \(k1\) 更靠后,所以随着 \(j\) 的增加,\(k1\) 会比 \(k2\) 更早从范围\([j-Li,Si-1]\)中排除。如果还满足\(F[i-1,k1]-Pi*k1<=F[i-1,k2]-Pi*k2\)那么就意味着 k2 不但比 k1 优,还比 k1 的存活时间更长。在这种情况下,k1 就是一个无用的决策,应该被排除出候选集合。综上所述,我们可以维护一个决策点 k 的单调递增。数值\(F[i-1,k]-Pi*k\) 单调递减的队列。只有这个队列中的决策才有可能在某一时刻成为最优决策。这个单调队列支持如下操作:
1.当 j 变大时,检查队头元素,把小于 j-Li 的决策出队。
2.需要查询最优决策时,队头即为所求。
3.有一个新的决策需要加入队列时,在队尾检查 F[i-1,k]-Pi*k 的单调性,把无用决策从队尾直接出队,最后把新决策加入队列。
在本题具体来说,当内循环开始时(j==Si),建立一个空的单调队列,把\(max(Si-Li,0),Si-1\)中的决策依次加入候选集合(执行操作 3)。对于每个 \(j=Si~k\),先在队头检查决策合法性(操作 1),然后取队头为最优决策(操作 2)进行状态转移。因为每个决策至多入队,出队一次,故转移的时间复杂队均弹 \(O(1)\)。整个算法的时间复杂度为 \(O(NM)\)。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int read()
{
int x=0,w=1;char ch=getchar();
while(ch>'9'||ch<'0') {if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*w;
}
int dp[110][16010];
int team[16010];
struct node{
int l,p,s;
}f[110];
int cmp(node p,node q)
{
return p.s<q.s;
}
int main()
{
int n=read(),k=read();
for(int i=1;i<=k;i++)
{
f[i].l=read();f[i].p=read();f[i].s=read();
}
sort(f+1,f+1+k,cmp);
for(int i=1;i<=k;i++)
{
int l=1,r=0;
for(int p=max(0,f[i].s-f[i].l);p<f[i].s;p++)
{
while(l<=r&&dp[i-1][team[r]]-f[i].p*team[r]<=dp[i-1][p]-f[i].p*p)
r--;
team[++r]=p;
}
for(int j=1;j<=n;j++)
{
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
if(j>=f[i].s)
{
while(l<=r&&team[l]<j-f[i].l) l++;
if(l<=r)
dp[i][j]=max(dp[i][j],dp[i-1][team[l]]+f[i].p*(j-team[l]));
}
}
}
cout<<dp[k][n];
}
[POJ1821]Fence(单调队列优化dp)的更多相关文章
- $Poj1821\ Fence\ $单调队列优化$DP$
Poj Acwing Description 有N块木板等待被M个工匠粉刷,每块木板至多被刷一次.第i个工匠要么不粉刷,要么粉刷包含木块Si的,长度不超过Li的连续的一段木板,每粉刷一块可以得到P ...
- poj1821 Fence(单调队列优化dp)
地址 一排N个木板,M个工匠站在不同位置$S_i$,每个人可以粉刷覆盖他位置的.最长长度为$L_i$木板段,每刷一个有$P_i$报酬.同一木板只刷一次.求最大报酬. 根据每个人的位置dp,设$f[i] ...
- POJ 1821 Fence(单调队列优化DP)
题解 以前做过很多单调队列优化DP的题. 这个题有一点不同是对于有的状态可以转移,有的状态不能转移. 然后一堆边界和注意点.导致写起来就很难受. 然后状态也比较难定义. dp[i][j]代表前i个人涂 ...
- poj 1821 Fence 单调队列优化dp
/* poj 1821 n*n*m 暴力*/ #include<iostream> #include<cstdio> #include<cstring> #incl ...
- 单调队列优化DP——习题收集
前言 感觉可以用单调队列优化dp的模型还是挺活的,开个随笔记录一些遇到的比较有代表性的模型,断续更新.主要做一个收集整理总结工作. 记录 0x01 POJ - 1821 Fence,比较适合入门的题, ...
- 单调队列优化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 ...
- 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在 ...
随机推荐
- 探讨vue的双向绑定原理及实现
1.vue的实现原理 vue的双向绑定是由数据劫持结合发布者-订阅者模式实现的,那么什么是数据劫持?vue是如何进行数据劫持的?说白了就是通过Object.defineProperty()来劫持对象属 ...
- Task4.文本表示:从one-hot到word2vec
参考:https://blog.csdn.net/wxyangid/article/details/80209156 1.one-hot编码 中文名叫独热编码.一位有效编码.方法是使用N位状态寄存器来 ...
- php similar_text()函数 语法
php similar_text()函数 语法 作用:计算两个字符串的相似度,并返回匹配字符的数目大理石平台厂家 语法:similar_text(string1,string2,percent) 参数 ...
- HTML计算机代码元素
计算机代码 1 2 3 4 5 6 var person = { firstName:"Bill", lastName:"Gates", ...
- Angular:实现组件间双向数据绑定
学过Angular的同学都知道,输入框通过[(ngModel)]实现双向数据绑定,那么父子组件间能不能实现双向数据绑定呢?答案是肯定的. Angular中,我们常常需要通过方括号[]和圆括号()实现组 ...
- Windows 环境下vue+webpack前端开发环境搭建
一.开发环境搭建 1.前端框架一般依赖node.js,我们首先要安装node.js. 2.由于许多npm 的源都在国外的地址,安装起来特别慢,所以我们这里利用淘宝的镜像服务器. 安装命令为:npm i ...
- Logistic Regression Algorithm解决分类问题
在线性回归算法中,我们看到,在training set中,输入矩阵X与向量y的值都是连续的.所以在二维空间中,我们可以用一条直线去模拟X与y的变化关系,寻找参数向量theta的取值.如根据房屋面积预测 ...
- 关于Visual Studio中书签Bookmark的一些问题
VS自带一个书签功能,但是有个大问题,没有导出功能,因为这个书签是保存在工程.suo文件中,所以在移动,分享,甚至其他情况下很不方便,甚至丢失. 在你分析一个较大的开源,做了30-50个关键代码书签, ...
- Linux中ssh及scp的连接
1. 当你想获取另外一台电脑上的数据时,可以使用这个命令 scp -P 10022 root@172.30.83.173:~/ubuntu1.tar ./ -r 代表传输文件夹,直接传文件可以不加 ...
- hacking 学习站
综合 idf实验室:http://ctf.idf.cn/ writeup: 部分参见本博 网络信息安全攻防学习平台:http://hackinglab.cn/ writeup: 部分参见本博 WeCh ...