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相关推荐

  1. 【BZOJ】3956 Count 单调栈+ST表

    题目传送门 挺有思想的一题,但如果弄清楚了思路这题还是挺简单的. 首先我们可以发挥一下自己的脑洞,发现所有的好集对不可能相交. 那么我们可以刷两遍单调栈,求出每个点作为区间左端点或右端点的次数. 对于 ...

  2. P3246 [HNOI2016]序列(莫队+单调栈+ST表)

    [HNOI2016]序列 Tea神题解 Kelin神题解 对于莫队算法最主要的是如何快速算出[l,r]→[l,r+1][l,r]\to[l,r+1][l,r]→[l,r+1]对答案的贡献的变化. 当询 ...

  3. 【BZOJ3956】Count,单调栈+ST表维护区间最大值

    Time:2016.08.11 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: TA爷眼中的水题 首先有个特别的结论 总共的点对数不会超过2n 因为对于元素i来说,如果只考虑与比它高 ...

  4. hdu6989 (莫队+单调栈+ST表)

    题意: 求l-r之间所有区间最大值最小值之和的期望,除法按照逆元来求; 题解: 看之前刚补的一道题目,那道题目跟这道题差不多,解释都在下面的链接中. [HNOI2016]序列 就是取余把人取傻了. # ...

  5. POJ 1821 Fence ★(单调队列优化DP)

    题目大意:有一道线性篱笆由N个连续的木板组成.有K个工人,你要叫他们给木板涂色.每个工人有3个参数:L 表示 这个工人可以涂的最大木板数目,S表示这个工人站在哪一块木板,P表示这个工人每涂一个木板可以 ...

  6. 洛谷 P4544 [USACO10NOV]Buying Feed G)(单调队列优化DP)

    题目链接:P4544 [USACO10NOV]Buying Feed G 建议做这题前先做下这题P1886 滑动窗口 /[模板]单调队列 我们可以用dp[i][j]表示当前走到前i个点,已经买了j吨饲 ...

  7. 浅谈单调队列优化的DP

    为什么都是浅谈?深入就掉坑啊,掉坑就要填坑啊,填坑就会发现又挖了更多的坑啊,然后恶性循环啊. 这个坑必须要填的,拖了这么久了. 先拿TYVJ 1305来说吧,此题具体的题面没找到,代码简单的对拍了一下 ...

  8. 【DP】【单调队列优化】修剪草坪

    题目描述 在一年前赢得了小镇的最佳草坪比赛后,约翰变得懒惰了,再也没有修剪过草坪.现在,新一轮的比赛又开始了,约翰希望能够再次夺冠.然而,约翰家的草坪非常脏乱,因此,约翰需要让他的奶牛来完成这项工作. ...

  9. hdu 4362(单调队列优化dp)

    题意:有m个阶段,每个阶段都有n个龙珠,当在某一阶段选择一个龙珠,该阶段其他龙珠都会消失.给出两个m*n的矩阵,第一个矩阵表示消灭第i个阶段第j个龙珠的位置,第二个矩阵表示取第i个阶段第j个龙珠消耗的 ...

最新文章

  1. NanoPi NEO Air使用十三:使用自带的fbtft驱动点亮SPI接口TFT屏幕,ST7789V,模块加载的方式
  2. 手动制作linux live,Linux下Live USB如何制作
  3. P3723 [AH2017/HNOI2017]礼物 FFT + 式子化简
  4. JDBC学习笔记 day1
  5. 重磅!2021年考研国家线公布!
  6. Matplotlib作业2
  7. 冷知识 —— 地名的解释
  8. lisp用entmake生产圆柱体_蚌埠踏步板钢盖板沟盖板生产加工厂家材质齐全-老友网...
  9. namenode倒换原因分析
  10. 微信内提示浏览器打开遮罩层
  11. python中shape 0_Python错误:找到包含0个样本(shape =(0,262))的数组,同时至少需要1个...
  12. light oj 1224
  13. [源码和文档分享]基于HTML5和JS实现的在线电子钢琴网页版
  14. android espresso 教程,Android Espresso入门到自动搞定
  15. 数据采集 - 获取【码市】最新发布需求,并实时通知用户 案例二
  16. py函数式编程(高阶函数map/reduce/filter/sorted、闭包函数/返回函数、匿名函数lamber、@装饰器decorator、偏函数functool.partial())
  17. 嵌入式Linux容器技术
  18. GPU深度发掘 -- GPGPU数学基础教程
  19. 涂鸦 opengl简单应用1
  20. 程序人生-hello`s P2P

热门文章

  1. 并发服务器模型——多进程服务器
  2. 好大夫王航:长尾开发者应尽快接入百度轻应用
  3. ext2.0 主体皮肤 (xtheme-black)
  4. 【opencv有趣应用】基于MobileNet + SSD的物体检测
  5. mybatis中SqlSession一定要关闭
  6. LSTM TF核心实现代码笔记
  7. 【研究方向是SDN该怎么做?】软件定义网络(SDN)的安全挑战和机遇
  8. 独热编码 one-hot Encoding
  9. CV之Harris特征点检测器-兴趣点检测(详解)
  10. python列表反向_python反向列表