ZOJ 3650 Toy Blocks(DP + 线段树优化转移)
来源:互联网 发布:林彪军事才能 知乎 编辑:程序博客网 时间:2024/05/23 01:23
题目链接:Click here~~
题意:
给出 n 个多米诺骨牌的 X 坐标以及高度 H,每次你可以选任意一张向左推或向右推,推倒后,会产生连锁反应,问最少几次能把所有的骨牌推倒。
解题思路:
先预处理出每张牌向 左/右 推能推到的最远位置,记为 l[i] 和 r[i]。这步可以通过递推的方法在均摊总复杂度为 O(n) 下得到。
然后 dp[i][dir] 表示前 i 张牌推倒 && 第 i 张牌倒的方向为 dir 的最少次数。
如果循环方向为从 1->n 的话,dp[i][0] = min(dp[i][l[i]-1]) + 1。这个应该不难想出来,因为 dp[i-1][dir] <= dp[i][dir] ,所以一定能推越远越好。
dp[i][1] = min ( min{dp[j][1]} , min(dp[i-1]) + 1 ) (j < i && r[j] >= i)。
即,如果向右倒的话,考虑是别人推倒自己,还是自己推倒自己。{ }内的部分要用线段树优化一下,使转移的复杂度为 O(logn)。
好像存在O(1)的转移写法,但是看不懂。还有就是{ }内的部分可以用树状数组来实现
#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;const int N = 1e5 + 3;pair<int,int> a[N];int l[N],r[N],dp[N][2];void pre(int n){ for(int i=1;i<=n;i++) l[i] = r[i] = i; for(int i=2;i<=n;i++) { int k = i; while(l[k] != 1 && a[i].first-a[l[k]-1].first <= a[i].second) k = l[k] - 1; l[i] = l[k]; } for(int i=n-1;i>=1;i--) { int k = i; while(r[k] != n && a[r[k]+1].first-a[i].first <= a[i].second) k = r[k] + 1; r[i] = r[k]; }}inline void check_min(int &a,int b){ a = a < b ? a : b;}#define lson u<<1#define rson u<<1|1struct Seg{ int l,r; int mmin,lazy; inline int mid(){ return l + r >> 1; }}T[N<<2];void build(int u,int l,int r){ T[u].l = l , T[u].r = r; T[u].mmin = T[u].lazy = N; if(l == r - 1) return ; int m = T[u].mid(); build(lson,l,m); build(rson,m,r);}void push_up(int u){ T[u].mmin = min(T[lson].mmin,T[rson].mmin);}void push_down(int u){ if(T[u].lazy == N) return ; check_min(T[lson].mmin,T[u].lazy); check_min(T[rson].mmin,T[u].lazy); check_min(T[lson].lazy,T[u].lazy); check_min(T[rson].lazy,T[u].lazy); T[u].lazy = N;}void updata(int u,int l,int r,int up){ if(T[u].l == l && T[u].r == r) { check_min(T[u].mmin,up); check_min(T[u].lazy,up); return ; } push_down(u); int m = T[u].mid(); if(r <= m) updata(lson,l,r,up); else if(l >= m) updata(rson,l,r,up); else updata(lson,l,m,up) , updata(rson,m,r,up); push_up(u);}int query(int u,int l){ if(T[u].l == l && T[u].r == l+1) return T[u].mmin; push_down(u); int m = T[u].mid(); if(l < m) return query(lson,l); else return query(rson,l);}int main(){ int n; while(~scanf("%d",&n)) { for(int i=1;i<=n;i++) scanf("%d%d",&a[i].first,&a[i].second); sort(a+1,a+1+n); pre(n); build(1,1,n+1); dp[0][0] = dp[0][1] = 0; for(int i=1;i<=n;i++) { dp[i][0] = min(dp[l[i]-1][0],dp[l[i]-1][1]) + 1; dp[i][1] = min(dp[i-1][0],dp[i-1][1]) + 1; check_min(dp[i][1],query(1,i)); updata(1,i,r[i]+1,dp[i][1]); } printf("%d\n",min(dp[n][0],dp[n][1])); } return 0;}
阅读全文
0 0
- ZOJ 3650 Toy Blocks(DP + 线段树优化转移)
- ZOJ 3650 Toy Blocks(DP + 线段树优化转移)
- ZOJ 3650 Toy Blocks(线段树+DP)
- zoj 2900 DP(线段树优化)
- ZOJ Toy Blocks
- ZOJ 3650(多米诺骨牌 dp + 线段树优化)
- ZOJ 3349 Special Subsequence(DP+线段树优化)
- ZOJ 3349 Special Subsequence(线段树优化DP)
- zoj 3349 Special Subsequence(dp+线段树优化)
- ZOJ 3349 Special Subsequence(DP+线段树优化)
- zoj 3349 简单DP 线段树或树状数组优化
- ZOJ 3349 Special Subsequence【dp+线段树优化】
- ZOJ 3632 Watermelon Full of Water(dp+线段树或单调队列优化)
- zoj Special Subsequence 3349 (DP+线段树优化) 好题***
- ZOJ 3349线段树+DP
- POJ 3734 Blocks(矩阵优化+DP)
- HNOI2008——玩具装箱toy(斜率优化DP)
- BZOJ1010 [HNOI2008]玩具装箱toy(斜率优化dp)
- Ligerid 遇到的一些问题
- 右键没有WinRAR压缩的解决方法
- MVP在RecyclerView中的使用
- 使用axios上传照片
- c++之继承与派生
- ZOJ 3650 Toy Blocks(DP + 线段树优化转移)
- 复制含有随机指针节点的链表
- java字符串
- input框回车事件
- 数据结构-03
- 每天一点MySQL-数据类型
- 批量文件重命名
- C++ 嵌入汇编 获取CPU信息
- 数据结构之图的遍历(BFS+DFS)