题解-[NOI2005]瑰丽华尔兹
题解-[NOI2005]瑰丽华尔兹
\(n\times m\) 的矩阵。以 \((x,y)\) 为起点。一共 \(k\) 段时间,每段时间为 \([s_i,t_i](t_i+1=s_{i+1})\),每秒可以向 \(d_i\) 方向运动一个单位(不能超出矩阵,不能走到给出矩阵的障碍物处,\(d=\{1,2,3,4\}\) 分别表示上下左右)或不动,求最后运动最长总距离。
数据范围:\(1\le n,m\le 200\),\(1\le k\le 200\),\(1\le s_i\le t_i\le 4\times 10^4\)。
非常引人入胜的一道题,表明上很毒瘤,其实故事情节生动,题目做法巧妙,代码长而不烦。完美啊!连我这个小蒟蒻都一次过了,除了在 \(\texttt{vector}\) 开队列大小上出了点小问题。
很明显可以 \(\texttt{dp}\):
\(f_{w,i,j}\) 表示第 \(w\) 段时间,走到 \((i,j)\) 这个格子时的最长路长度。
\(f_{w,i,j}\) 可以由 \(f_{w-1,i',j'}\) 推得。
如果直接野蛮递推(暴力找同行(列)的 \(i'\) 或 \(j'\)),时间复杂度为 \(\Theta(knm(n+m))\) 稳炸。
考虑到递推时的单向性和单调性,想到可以用单调队列。
对于每个 \(w\),\(d_w\) 不同,所以可以分类讨论不同方向时的 \(\texttt{dp}\) 递推方法。
举例:假设 \(d_w=4\),即方向为右。
因为是横向递推的,所以可以单独考虑每一行。
怎么用单调队列呢?
- 队列中存的是当前格左端 从头到尾
期望贡献单调递减的 列下标。 - 清空 \(w\) 时间段长度内不可达到的或与当前格被障碍物隔绝的列下标。
- 遍历列的同时维护单调队列并求得 \(f_{w,i,j}\) 递推值。
这东西好想却难讲,于是蒟蒻画了个图:

其实绿色格子上也应该有数字,也应该考虑是否放进单调队列,但是那样问题会稍微复杂一些。
设单调队列的头为 \(qtop\),如上图中 \(queue=\{3,5\}\),\(qtop=3\)。
所以递推转移方程为:
\]
所以上图中:
\]
所以当 \(d_w=4\) 时的代码:
for(re int i=1;i<=n;i++){
l=1,r=0;
for(re int j=1;j<=m;j++){
if(G[i][j]){l=r+1;continue;} //如果遇到障碍物,清空数组
while(l<=r&&q[l]<j-mv.se) l++; //把该时间段走不到的排除(时间太少了)
while(l<=r&&f[p^1][i][q[r]]-q[r]<=f[p^1][i][j]-j) r--; //维护队列期望贡献单调递减
q[++r]=j,f[p][i][j]=max(f[p][i][j],f[p^1][i][q[l]]+j-q[l]); //队列加入j,一路递推dp
}
}
至于另外 \(3\) 个方向,自己拿纸笔模拟模拟即可知。
代码实现的时候,其实 \(w\) 这一维可以用滚动数组优化到 \(\Theta(1)\)。
总时间复杂度为 \(\Theta(knm)\),空间复杂度为 \(\Theta(nm)\)。
Code
#include <bits/stdc++.h>
using namespace std;
//Start
#define re register
#define il inline
#define mk make_pair
#define mt make_tuple
#define pb push_back
#define db double
#define lng long long
#define fi first
#define se second
const int inf=0x3f3f3f3f;
//Data
const int N=200;
int n,m,x,y,k,G[N+7][N+7];
vector<pair<int,int>> Mv;
int f[2][N+7][N+7];
char s[N+7];
//Main
int main(){
scanf("%d%d%d%d%d",&n,&m,&x,&y,&k);
for(re int i=1;i<=n;i++){
scanf("%s",s+1);
for(re int j=1;j<=m;j++) G[i][j]=(s[j]=='x');
}
for(re int i=1,s,t,d;i<=k;i++){
scanf("%d%d%d",&s,&t,&d);
Mv.pb(mk(d,t-s+1)); // 重要的是时间段长度
}
re int p=0,l,r;
re vector<int> q(max(n,m)+7);
//我原来这里竟然写成了 re vector<int> q(n+7);,如果 n<m 就 RE 了
for(re int i=1;i<=n;i++)
for(re int j=1;j<=m;j++) f[p][i][j]=-inf;
f[p][x][y]=0;
for(re auto mv:Mv){
p^=1; //滚动
for(re int i=1;i<=n;i++)
for(re int j=1;j<=m;j++) f[p][i][j]=-inf;
if(mv.fi==1){ // 上
for(re int j=1;j<=m;j++){
l=1,r=0;
for(re int i=n;i>=1;i--){
if(G[i][j]){l=r+1;continue;}
while(l<=r&&q[l]>i+mv.se) l++;
while(l<=r&&f[p^1][q[r]][j]+q[r]<=f[p^1][i][j]+i) r--;
q[++r]=i,f[p][i][j]=max(f[p][i][j],f[p^1][q[l]][j]+q[l]-i);
}
}
} else if(mv.fi==2){ // 下
for(re int j=1;j<=m;j++){
l=1,r=0;
for(re int i=1;i<=n;i++){
if(G[i][j]){l=r+1;continue;}
while(l<=r&&q[l]<i-mv.se) l++;
while(l<=r&&f[p^1][q[r]][j]-q[r]<=f[p^1][i][j]-i) r--;
q[++r]=i,f[p][i][j]=max(f[p][i][j],f[p^1][q[l]][j]+i-q[l]);
}
}
} else if(mv.fi==3){ // 左
for(re int i=1;i<=n;i++){
l=1,r=0;
for(re int j=m;j>=1;j--){
if(G[i][j]){l=r+1;continue;}
while(l<=r&&q[l]>j+mv.se) l++;
while(l<=r&&f[p^1][i][q[r]]+q[r]<=f[p^1][i][j]+j) r--;
q[++r]=j,f[p][i][j]=max(f[p][i][j],f[p^1][i][q[l]]+q[l]-j);
}
}
} else if(mv.fi==4){ // 右-举的例子
for(re int i=1;i<=n;i++){
l=1,r=0;
for(re int j=1;j<=m;j++){
if(G[i][j]){l=r+1;continue;}
while(l<=r&&q[l]<j-mv.se) l++;
while(l<=r&&f[p^1][i][q[r]]-q[r]<=f[p^1][i][j]-j) r--;
q[++r]=j,f[p][i][j]=max(f[p][i][j],f[p^1][i][q[l]]+j-q[l]);
}
}
}
}
re int ans=-inf;
for(re int i=1;i<=n;i++)
for(re int j=1;j<=m;j++) ans=max(ans,f[p][i][j]);
printf("%d\n",ans);
return 0;
}
祝大家学习愉快!
题解-[NOI2005]瑰丽华尔兹的更多相关文章
- NOI2005瑰丽华尔兹
1499: [NOI2005]瑰丽华尔兹 Time Limit: 3 Sec Memory Limit: 64 MBSubmit: 893 Solved: 508[Submit][Status] ...
- luogu P2254 [NOI2005]瑰丽华尔兹
题目链接 luogu P2254 [NOI2005]瑰丽华尔兹 题解 为什么我我我不放放放bzoj的链接呢? 因为打的暴力啊,然后bzojT了呀QAQQQQQ(逃 然后luogu竟然过了呀呀呀 dp[ ...
- 【BZOJ1499】[NOI2005]瑰丽华尔兹 单调队列+DP
[BZOJ1499][NOI2005]瑰丽华尔兹 Description 你跳过华尔兹吗?当音乐响起,当你随着旋律滑动舞步,是不是有一种漫步仙境的惬意?众所周知,跳华尔兹时,最重要的是有好的音乐.但是 ...
- 单调队列优化DP || [NOI2005]瑰丽华尔兹 || BZOJ 1499 || Luogu P2254
题外话:题目极好,做题体验极差 题面:[NOI2005]瑰丽华尔兹 题解: F[t][i][j]表示第t时刻钢琴位于(i,j)时的最大路程F[t][i][j]=max(F[t-1][i][j],F[t ...
- bzoj1499[NOI2005]瑰丽华尔兹 单调队列优化dp
1499: [NOI2005]瑰丽华尔兹 Time Limit: 3 Sec Memory Limit: 64 MBSubmit: 1802 Solved: 1097[Submit][Status ...
- [Bzoj1499][NOI2005]瑰丽华尔兹[简单DP]
1499: [NOI2005]瑰丽华尔兹 Time Limit: 3 Sec Memory Limit: 64 MBSubmit: 1714 Solved: 1042[Submit][Status ...
- P2254 [NOI2005]瑰丽华尔兹
链接P2254 [NOI2005]瑰丽华尔兹 首先有个很朴素的\(dp\),设\(f_{i,j,k}\)表示\(k\)时刻地点\(i,j\)的最长长度. 然后这样不能优化,考虑利用一段连续时间是同一个 ...
- BZOJ 1499 [NOI2005] 瑰丽华尔兹 | 单调队列优化DP
BZOJ 1499 瑰丽华尔兹 | 单调队列优化DP 题意 有一块\(n \times m\)的矩形地面,上面有一些障碍(用'#'表示),其余的是空地(用'.'表示).每时每刻,地面都会向某个方向倾斜 ...
- BZOJ1499:[NOI2005]瑰丽华尔兹——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=1499 舞厅是一个N行M列的矩阵,矩阵中的某些方格上堆放了一些家具,其他的则是空地.钢琴可以在空地上滑 ...
随机推荐
- DOS基本命令(Windows下的基本命令部分)
一.cls(clear screen的简写) 命令作用:清屏屏幕 详细介绍:屏幕显示的所有字符信息都是存放在一个屏幕缓冲区中,cls命令的作用是清除屏幕上的文字,并将该缓冲区清空. 二.dir(dir ...
- 干货 MySQL常见的面试题 + 索引原理分析
常见的面试必备之MySQL索引底层原理分析: MySQL索引的本质 MySQL索引的底层原理 MySQL索引的实战经验 面试 1)问题:数据库中最常见的慢查询优化方式是什么? 回答:加索引 2)问题: ...
- C#设计模式-外观模式(Facade Pattern)
引言 在软件测试中,一般都是在功能测试稳定的情况下再进行UI自动化测试.或者进行性能测试.如果一个一个进行太麻烦,此时可以使用对外提供一个简单接口,通过这个接口可以访问内部一群接口.例如进行UI自动化 ...
- 厉害啊!第一次见到把Shiro运行流程写的这么清楚的,建议收藏起来慢慢看
前言 shiro是apache的一个开源框架,是一个权限管理的框架,实现 用户认证.用户授权. spring中有spring security (原名Acegi),是一个权限框架,它和spring依赖 ...
- 如何在MathType输入手写体a
作为强大的数学公式编辑器,MathType中还能设置各种样式,还支持自定义设置,给大家编辑公式提供了更多的便利.那么有用户问:要如何将输入的字母a变为手写体呢?下面就来一起学习. 输入手写体a的步骤如 ...
- 基于Python Requests的数据驱动的HTTP接口测试
发表于:2017-8-30 11:56 作者:顾翔 来源:51Testing软件测试网原创 http://www.51testing.com/html/69/n-3720769-2.html ...
- 【Vue】1.前端项目初始化
1.前提 安装nodejs: https://nodejs.org/en/, 安装LTS稳定版本 安装Vscode: https://code.visualstudio.com/ 2.安装Vue脚手架 ...
- centos克隆虚拟机
首先我们把所要克隆的虚拟机关机,然后在所要克隆的虚拟机上右键,选择管理,选择克隆,出现如下界面: 点击下一步,选择虚拟机的当前状态,继续点击下一步 接着选择创建完整克隆,选择这个时,表明克隆出来的这个 ...
- 【mq读书笔记】定时消息
mq不支持任意的时间京都,如果要支持,不可避免的需要在Broker层做消息排序,加上持久化方面的考量,将不可避免地带来巨大的性能消耗,所以rocketMQ只支持特定级别的延迟消息. 在Broker短通 ...
- 使用ssh远程连接命令行系统
1.进入shell窗口 2.ssh+用户名+@+ip 例如:ssh root@39.96.58.107 3.输入密码