机器人移动
机器人移动
在一个无限大的二维平面上有一个机器人。
初始时,机器人位于点 。
机器人可以执行四种行动指令:
- U — 从 移动到 ;
- D — 从 移动到 ;
- L — 从 移动到 ;
- R — 从 移动到 。
给定一个长度为 的指令序列,指令编号 ,机器人将按顺序依次执行序列中的每个行动指令。
我们希望机器人最终抵达目标地点 。
为了达成这一目的,我们可能需要对指令序列进行修改。
每次修改可以选择其中一个指令,并将其替换为四种指令之一。
注意,只能对序列中的指令进行替换,不得随意删除指令或添加额外指令。
不妨设经过修改的指令中,编号最小的指令编号为 ,编号最大的指令编号为 。
我们定义修改成本为 。
例如,将 RRRRRRR 修改为 RLRRLRL ,则编号为 的指令经过了修改,修改成本为 。
请你计算,为了使得机器人能够最终抵达目标点 ,所需花费的最小修改成本。
如果不需要对序列进行修改,则成本为 。
输入格式
第一行包含整数 。
第二行包含一个长度为 的字符串,表示指令序列,字符串中只包含 U,D,L ,R。
第三行包含两个整数 ,表示机器人的目标位置为 。
输出格式
输出一个整数,表示最小修改成本。
如果无论如何修改,机器人都无法抵达目标位置,则输出 。
数据范围
前四个测试点满足 。
所有测试点满足 ,。
输入样例1:
5 RURUU -2 3
输出样例1:
3
输入样例2:
4 RULR 1 1
输出样例2:
0
输入样例3:
3 UUU 100 100
输出样例3:
-1
解题思路
这题是用二分来枚举答案。首先看看答案是否满足二段性。如果有最小的代价,那么可以发现如果代价大于,那么机器人也一定可以移动到终点(把区间长度取大些,用区间内的某个字符与端点进行交换)。如果代价小于,那么机器人不可以移动到终点。因此答案具有二段性。
我们二分所需要的代价,假设为,那么我们在check的时候,如果代价最多为,意味着所有的操作指令一定在长度为的区间内的,因此我们需要枚举序列中所有长度为的区间。在枚举每一个长度为的区间时,我们需要快速判断如果只修改这个区间内的指令,能否让机器人走到终点,这个时间复杂度应该是。
我们可以把整个序列分成三段:
机器人每次都有上下左右四个方向的向量之一,如果要走到的最终位置,就是每一次指令对应的向量的和。其中,左右为同一个向量维度(水平方向),向左就减,向右就加。上下为同一个维度(竖直方向),向上就加,向下就减。
能不能到终点其实就是算这三段的向量和(分别算水平方向与竖直方向的)。由于我们只改变长度为的这一段,另外两段是不会改变的,因此是一个定值。然后长度为的区间每一个位置都可以设置为任意的指令,因此是一个变量。因此得到的值应该是一个区间范围,我们只需要判断在这个区间范围内,是否包含到终点的值。
要求某部分区间的和,可以用前缀和。不过这里需要开两个前缀和数组,分别求水平方向和竖直方向的前缀和。
由于是定值,因此我们先从起点根据这个和走到某一个点。假设终点是,我们要从走到,只能借助长度为这个区间的指令。因此我们要判断的是从能否恰好走步,走到。
由于求的是曼哈顿距离,因此要从到的曼哈顿距离为,即至少需要走步。因为每走一步最多让这两点的距离减,要让距离变成,因此要满足。因此我们可以构造出一条路径,使得恰好走步,从走到。对于剩余的步数,这个值应该是偶数,因为此时到的距离为,如果是奇数,那么必然会使到的距离变成或。偶数的话可以构造出和的情况,使得距离恰好抵消。
因此判断能否通过这个长度的区间,使得走到,要满足两个条件:
AC代码如下:
1 #include <cstdio> 2 #include <cmath> 3 #include <algorithm> 4 using namespace std; 5 6 const int N = 2e5 + 10; 7 8 int n, x, y; 9 char str[N]; 10 int sx[N], sy[N]; 11 12 bool check(int len) { 13 for (int i = 1; i + len - 1 <= n; i++) { 14 int j = i + len - 1; 15 int xx = sx[n] - (sx[j] - sx[i - 1]), yy = sy[n] - (sy[j] - sy[i - 1]); // 相当于求s1和s3两个区间的和 16 if (abs(x - xx) + abs(y - yy) <= len && (len - abs(x - xx) - abs(y - yy)) % 2 == 0) return true; 17 } 18 19 return false; 20 } 21 22 int main() { 23 scanf("%d %s %d %d", &n, str + 1, &x, &y); 24 25 if (abs(x - y) > n || (n - x - y) % 2) { 26 printf("-1"); 27 return 0; 28 } 29 30 for (int i = 1; i <= n; i++) { 31 sx[i] = sx[i - 1], sy[i] = sy[i - 1]; 32 if (str[i] == 'U') sy[i]++; 33 else if (str[i] == 'D') sy[i]--; 34 else if (str[i] == 'L') sx[i]--; 35 else sx[i]++; 36 } 37 38 int l = 0, r = n; 39 while (l < r) { 40 int mid = l + r >> 1; 41 if (check(mid)) r = mid; 42 else l = mid + 1; 43 } 44 45 printf("%d", l); 46 47 return 0; 48 }
参考资料
AcWing 4217. 机器人移动(AcWing杯 - 周赛):https://www.acwing.com/video/3692/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16063998.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
2021-04-01 在堆区申请二维数组的方法