[BZOJ 1499][NOI 2005]瑰丽华尔兹(DP+单调队列优化)
2015-04-25 11:11
381 查看
题目链接
http://www.lydsy.com/JudgeOnline/problem.php?id=1499思路
一个很显然的O(nmT)O(nmT)的做法就是令f[t][i][j]f[t][i][j]表示时刻tt时,钢琴位于(i,j)(i,j)处时,从时刻11到tt的最长滑行路程。很容易得到DP方程f[t][i][j]=max{f[t−1][i][j],f[t−1][ilast][jlast]+1}f[t][i][j]=\max \{ f[t-1][i][j],f[t-1][i_{last}][j_{last}]+1\}
这样做显然太慢,由于钢琴的移动方向是在一段一段的时间内是相同的,因此可以考虑成段DP。令f[t][i][j]f[t][i][j]表示第tt段时间时,钢琴位于(i,j)(i,j)处时,从第11段时间到第tt段时间的最长滑行路程。
f[t][i][j]=max{f[t−1][ilast][jlast]+dist{(ilast,jlast),(i,j)}}f[t][i][j]=\max \{ f[t-1][i_{last}][j_{last}]+dist\{(i_{last},j_{last}),(i,j)\}\}
下面举一个简单例子,当前这段时间内移动方向都是朝右,来讲讲如何利用单调队列优化
可以列出DP方程
f[t][i][j]=max{f[t−1][i][j′]+(j−j′)}=j+max{f[t−1][i][j′]−j′},j−j′≤startt−endt+1f[t][i][j]=\max \{ f[t-1][i][j']+(j-j')\}=j+\max \{ f[t-1][i][j']-j'\},j-j'\leq start_t-end_t+1
第tt段移动方向对应于时间段[startt,endt][start_t,end_t]
jj是个常量,因此我们就是要找到最大的max{f[t−1][i][j′]−j′}\max \{ f[t-1][i][j']-j'\},我们可以维护一个单调队列,保存t−1t-1时刻的所有可行状态的ff值与j′j',保证j′j'单调递增,ff值单调递减,在dp到第tt段时,首先枚举行ii,然后从左到右来枚举jj,并时刻保证队首的j′j'满足限制条件j−j′≤startt−endt+1j-j'\leq start_t-end_t+1,这样的单调队列的队首显然是最优的,用此时的队首的f[t−1][i][j′]f[t-1][i][j']来更新答案。
其他三个方向的DP过程也类似,这样做最终的时间复杂度是O(nmk)O(nmk)
代码
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> #include <queue> #define MAXN 1000 #define MAXK 300 #define INF 0x3f3f3f3f using namespace std; typedef pair<int,int>pr; int xx[]={-1,1,0,0},yy[]={0,0,-1,1}; int n,m,K,ans,cur; int sx,sy; bool mp[MAXN][MAXN]; int f[2][MAXN][MAXN]; struct Segment { int st,ed,dir; }seg[MAXN]; bool operator<(Segment a,Segment b) { return a.st<b.st; } struct Monoque { deque<pr>q; void clear() { q.clear(); } void Insert(int pos,int val) { while(!q.empty()&&q.back().second<val) q.pop_back(); q.push_back(make_pair(pos,val)); } int query(int pos,int limit) { while(!q.empty()&&pos-q.front().first>limit) q.pop_front(); return q.front().second; } }monoq; void update(int time,int cur,int x,int y,int t) //第t段状态区间 { if(mp[x][y]) //(x,y)是障碍物 { f[cur][x][y]=-INF; monoq.clear(); return; } monoq.Insert(time,f[cur^1][x][y]-time); f[cur][x][y]=monoq.query(time,seg[t].ed-seg[t].st+1)+time; ans=max(ans,f[cur][x][y]); } int main() { scanf("%d%d%d%d%d",&n,&m,&sx,&sy,&K); char s[MAXN]; for(int i=1;i<=n;i++) { scanf("%s",s+1); for(int j=1;j<=m;j++) { mp[i][j]=s[j]=='x'; f[0][i][j]=-INF; } } f[0][sx][sy]=0; for(int i=1;i<=K;i++) scanf("%d%d%d",&seg[i].st,&seg[i].ed,&seg[i].dir); sort(seg+1,seg+K+1); for(int i=1;i<=K;i++) { cur^=1; if(seg[i].dir==1) //上 for(int y=1;y<=m;y++) { monoq.clear(); for(int x=n;x>=1;x--) update(n-x,cur,x,y,i); } else if(seg[i].dir==2) //下 for(int y=1;y<=m;y++) { monoq.clear(); for(int x=1;x<=n;x++) update(x,cur,x,y,i); } else if(seg[i].dir==3) //左 for(int x=1;x<=n;x++) { monoq.clear(); for(int y=m;y>=1;y--) update(m-y,cur,x,y,i); } else for(int x=1;x<=n;x++) { monoq.clear(); for(int y=1;y<=m;y++) update(y,cur,x,y,i); } } printf("%d\n",ans); return 0; }
相关文章推荐
- Bzoj - 1499 [Noi2005] 瑰丽华尔兹 [DP][单调队列优化]
- bzoj1499 [NOI2005]瑰丽华尔兹 (单调队列优化DP)
- bzoj1499[NOI2005]瑰丽华尔兹 单调队列优化dp
- 【bzoj1499】[NOI2005]瑰丽华尔兹 【单调队列优化dp】
- 【bzoj1499】[NOI2005]瑰丽华尔兹(dp+单调队列优化)
- bzoj1499: [NOI2005]瑰丽华尔兹&&codevs1748 单调队列优化dp
- BZOJ 1499 [NOI2005] 瑰丽华尔兹 | 单调队列优化DP
- [BZOJ1499][NOI2005]瑰丽华尔兹(单调队列优化DP)
- bzoj 1499: [NOI2005]瑰丽华尔兹【dp+单调队列】
- 【BZOJ1499】[NOI2005]瑰丽华尔兹 单调队列+DP
- [BZOJ1499][NOI2005]瑰丽华尔兹 dp+单调队列
- [DP 暴力 || ST表 || 单调队列] BZOJ 1499 [NOI2005]瑰丽华尔兹
- bzoj1499 [NOI2005]瑰丽华尔兹(dp+单调队列)
- bzoj1499 [NOI2005]瑰丽华尔兹(luoguP2254)(dp+单调队列)
- 【noi2005试题】瑰丽华尔兹 单调队列优化DP
- BZOJ 1499 NOI2005 瑰丽华尔兹 单调队列
- BZOJ 1499 NOI2005 瑰丽华尔兹 单调队列
- BZOJ1499 [NOI2005]瑰丽华尔兹 【单调队列优化dp】
- [BZOJ1499][NOI2005][DP+优化]瑰丽华尔兹
- NOI 2005 瑰丽华尔兹(三维DP + 单调队列优化)