POJ1821 单调队列//ST表 优化dp
http://poj.org/problem?id=1821
当我们在考虑内层循环j以及决策k的时候,我们可以把外层变量i看作定值,以此来优化dp状态转移方程。
题意 有n个工人准备铺m个连续的墙,每个工人有他必须图的一面墙壁Si,最多连续铺Li,每铺一个就花费Ci的钱,问最多要多少钱;
朴素算法很好想,就dp[i][j]维护i工人到这j层墙壁的最大值,对于每个工人去枚举他涂墙壁的开头和结尾然后更新即可。
时间复杂度O(NMM) M的范围是16000,很显然会T,我们考虑状态转移方程。
对于每个工人,dp[i][j]的更新是寻找一个k使得dp[i - 1][k - 1] + (j - k + 1 ) * P 最大;
在这个转移方程里,我们将i看作定值,除了状态变量j之外还有一个决策j,看似很难处理,我们将方程变形.
dp[i][j]的更新变为 max(dp[i - 1][k - 1] - (k - 1) * P) + j * P;
在这一层中,最大值的寻找仅和k有关,而k事实上对每一个i都是可以预处理出来的,在j查询的时候只有范围变动,问题就变成了常规的优化区间最大值的问题。
这里附上用ST表优化和单调队列优化的两种方法。
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; const double eps = 1e-9; const int maxn = 110; const int maxm = 20010; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,M,tmp,K; inline int read() {int now=0;register char c=getchar();for(;!isdigit(c);c=getchar());for(;isdigit(c);now=now*10+c-'0',c=getchar());return now; } struct Node{int L,P,S; }node[maxn]; int dp[2][maxm]; bool cmp(Node a,Node b){return a.S < b.S; } int DP[maxm][20]; int mm[maxm]; int num[maxm]; void initRMQ(int n,int b[]){mm[0] = -1;for(int i = 1; i <= n ; i ++){mm[i] = ((i & (i - 1)) == 0) ? mm[i - 1] + 1:mm[i - 1];DP[i][0] = b[i];}for(int j = 1; j <= mm[n]; j ++){for(int i = 1; i + (1 << j) - 1 <= n ; i++){DP[i][j] = max(DP[i][j - 1],DP[i + (1 << (j - 1))][j - 1]);}} } int rmq(int x,int y){int k = mm[y - x + 1];return max(DP[x][k],DP[y - (1 << k) + 1][k]); } int main() {while(~Sca2(N,K)){For(i,1,K){scanf("%d%d%d",&node[i].L,&node[i].P,&node[i].S);}sort(node + 1,node + 1 + K,cmp);Mem(dp,0);For(i,1,K){Mem(num,0);Mem(dp[i & 1],0);for(int k = max(node[i].S - node[i].L + 1,1); k <= node[i].S; k ++){num[k] = dp[i - 1 & 1][k - 1] - node[i].P * (k - 1);}initRMQ(node[i].S,num);For(j,1,N){dp[i & 1][j] = max(dp[i - 1 & 1][j],dp[i & 1][j - 1]);if(j >= node[i].S && j <= node[i].S + node[i].L - 1){dp[i & 1][j] = max(dp[i & 1][j],rmq(max(j - node[i].L + 1,1),node[i].S) + node[i].P * j);}} }Pri(dp[K & 1][N]);}#ifdef VSCodesystem("pause");#endifreturn 0; }
ST表优化
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; const double eps = 1e-9; const int maxn = 110; const int maxm = 20010; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,M,tmp,K; inline int read() {int now=0;register char c=getchar();for(;!isdigit(c);c=getchar());for(;isdigit(c);now=now*10+c-'0',c=getchar());return now; } struct Node{int L,P,S; }node[maxn]; int dp[2][maxm]; bool cmp(Node a,Node b){return a.S < b.S; } int Queue[maxm]; int head,tail; int main() {while(~Sca2(N,K)){For(i,1,K){scanf("%d%d%d",&node[i].L,&node[i].P,&node[i].S);}sort(node + 1,node + 1 + K,cmp);Mem(dp,0);For(i,1,K){head = 1; tail = 0;Mem(dp[i & 1],0);for(int k = max(node[i].S - node[i].L + 1,1); k <= node[i].S; k ++){int ans = dp[i - 1 & 1][k - 1] - node[i].P * (k - 1);while(head <= tail && dp[i - 1 & 1][Queue[tail] - 1] - node[i].P * (Queue[tail] - 1)<= ans) tail--;Queue[++tail] = k;}For(j,1,N){dp[i & 1][j] = max(dp[i - 1 & 1][j],dp[i & 1][j - 1]);if(j >= node[i].S){while(head <= tail && Queue[head] < j - node[i].L + 1) head++;if(head <= tail) dp[i & 1][j] = max(dp[i & 1][j],dp[i - 1 & 1][Queue[head] - 1] + (j - Queue[head] + 1) * node[i].P);}} }Pri(dp[K & 1][N]);}#ifdef VSCodesystem("pause");#endifreturn 0; }
单调队列优化
值得一提的是单调队列的查询和处理的时间都是线性的,总时间复杂度为O(NM),而ST表的预处理要用到nlnn,所以用时会比ST表快一些
转载于:https://www.cnblogs.com/Hugh-Locke/p/9643832.html
POJ1821 单调队列//ST表 优化dp相关推荐
- 【BZOJ】3956 Count 单调栈+ST表
题目传送门 挺有思想的一题,但如果弄清楚了思路这题还是挺简单的. 首先我们可以发挥一下自己的脑洞,发现所有的好集对不可能相交. 那么我们可以刷两遍单调栈,求出每个点作为区间左端点或右端点的次数. 对于 ...
- P3246 [HNOI2016]序列(莫队+单调栈+ST表)
[HNOI2016]序列 Tea神题解 Kelin神题解 对于莫队算法最主要的是如何快速算出[l,r]→[l,r+1][l,r]\to[l,r+1][l,r]→[l,r+1]对答案的贡献的变化. 当询 ...
- 【BZOJ3956】Count,单调栈+ST表维护区间最大值
Time:2016.08.11 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: TA爷眼中的水题 首先有个特别的结论 总共的点对数不会超过2n 因为对于元素i来说,如果只考虑与比它高 ...
- hdu6989 (莫队+单调栈+ST表)
题意: 求l-r之间所有区间最大值最小值之和的期望,除法按照逆元来求; 题解: 看之前刚补的一道题目,那道题目跟这道题差不多,解释都在下面的链接中. [HNOI2016]序列 就是取余把人取傻了. # ...
- POJ 1821 Fence ★(单调队列优化DP)
题目大意:有一道线性篱笆由N个连续的木板组成.有K个工人,你要叫他们给木板涂色.每个工人有3个参数:L 表示 这个工人可以涂的最大木板数目,S表示这个工人站在哪一块木板,P表示这个工人每涂一个木板可以 ...
- 洛谷 P4544 [USACO10NOV]Buying Feed G)(单调队列优化DP)
题目链接:P4544 [USACO10NOV]Buying Feed G 建议做这题前先做下这题P1886 滑动窗口 /[模板]单调队列 我们可以用dp[i][j]表示当前走到前i个点,已经买了j吨饲 ...
- 浅谈单调队列优化的DP
为什么都是浅谈?深入就掉坑啊,掉坑就要填坑啊,填坑就会发现又挖了更多的坑啊,然后恶性循环啊. 这个坑必须要填的,拖了这么久了. 先拿TYVJ 1305来说吧,此题具体的题面没找到,代码简单的对拍了一下 ...
- 【DP】【单调队列优化】修剪草坪
题目描述 在一年前赢得了小镇的最佳草坪比赛后,约翰变得懒惰了,再也没有修剪过草坪.现在,新一轮的比赛又开始了,约翰希望能够再次夺冠.然而,约翰家的草坪非常脏乱,因此,约翰需要让他的奶牛来完成这项工作. ...
- hdu 4362(单调队列优化dp)
题意:有m个阶段,每个阶段都有n个龙珠,当在某一阶段选择一个龙珠,该阶段其他龙珠都会消失.给出两个m*n的矩阵,第一个矩阵表示消灭第i个阶段第j个龙珠的位置,第二个矩阵表示取第i个阶段第j个龙珠消耗的 ...
最新文章
- NanoPi NEO Air使用十三:使用自带的fbtft驱动点亮SPI接口TFT屏幕,ST7789V,模块加载的方式
- 手动制作linux live,Linux下Live USB如何制作
- P3723 [AH2017/HNOI2017]礼物 FFT + 式子化简
- JDBC学习笔记 day1
- 重磅!2021年考研国家线公布!
- Matplotlib作业2
- 冷知识 —— 地名的解释
- lisp用entmake生产圆柱体_蚌埠踏步板钢盖板沟盖板生产加工厂家材质齐全-老友网...
- namenode倒换原因分析
- 微信内提示浏览器打开遮罩层
- python中shape 0_Python错误:找到包含0个样本(shape =(0,262))的数组,同时至少需要1个...
- light oj 1224
- [源码和文档分享]基于HTML5和JS实现的在线电子钢琴网页版
- android espresso 教程,Android Espresso入门到自动搞定
- 数据采集 - 获取【码市】最新发布需求,并实时通知用户 案例二
- py函数式编程(高阶函数map/reduce/filter/sorted、闭包函数/返回函数、匿名函数lamber、@装饰器decorator、偏函数functool.partial())
- 嵌入式Linux容器技术
- GPU深度发掘 -- GPGPU数学基础教程
- 涂鸦 opengl简单应用1
- 程序人生-hello`s P2P