机器人移动
机器人移动
在一个无限大的二维平面上有一个机器人。
初始时,机器人位于点 $\left( {0,0} \right)$。
机器人可以执行四种行动指令:
- U — 从 $\left( {x,y} \right)$ 移动到 $\left( {x,y+1} \right)$;
- D — 从 $\left( {x,y} \right)$ 移动到 $\left( {x,y-1} \right)$;
- L — 从 $\left( {x,y} \right)$ 移动到 $\left( {x-1,y} \right)$;
- R — 从 $\left( {x,y} \right)$ 移动到 $\left( {x+1,y} \right)$。
给定一个长度为 $n$ 的指令序列,指令编号 $1 \sim n$,机器人将按顺序依次执行序列中的每个行动指令。
我们希望机器人最终抵达目标地点 $\left( {a,b} \right)$。
为了达成这一目的,我们可能需要对指令序列进行修改。
每次修改可以选择其中一个指令,并将其替换为四种指令之一。
注意,只能对序列中的指令进行替换,不得随意删除指令或添加额外指令。
不妨设经过修改的指令中,编号最小的指令编号为 $minID$,编号最大的指令编号为 $maxID$。
我们定义修改成本为 $maxID−minID+1$。
例如,将 RRRRRRR 修改为 RLRRLRL ,则编号为 $2,5,7$ 的指令经过了修改,修改成本为 $7−2+1=6$。
请你计算,为了使得机器人能够最终抵达目标点 $\left( {a,b} \right)$,所需花费的最小修改成本。
如果不需要对序列进行修改,则成本为 $0$。
输入格式
第一行包含整数 $n$。
第二行包含一个长度为 $n$ 的字符串,表示指令序列,字符串中只包含 U,D,L ,R。
第三行包含两个整数 $a,b$,表示机器人的目标位置为 $\left( {a,b} \right)$。
输出格式
输出一个整数,表示最小修改成本。
如果无论如何修改,机器人都无法抵达目标位置,则输出 $−1$。
数据范围
前四个测试点满足 $1 \leq n \leq 10$。
所有测试点满足 $1 \leq n \leq 2 \times {10}^{5}$,${−10}^{9} \leq {x,y} \leq {10}^{9}$。
输入样例1:
5 RURUU -2 3
输出样例1:
3
输入样例2:
4 RULR 1 1
输出样例2:
0
输入样例3:
3 UUU 100 100
输出样例3:
-1
解题思路
这题是用二分来枚举答案。首先看看答案是否满足二段性。如果有最小的代价$ans$,那么可以发现如果代价大于$ans$,那么机器人也一定可以移动到终点(把区间长度取大些,用区间内的某个字符与端点进行交换)。如果代价小于$ans$,那么机器人不可以移动到终点。因此答案具有二段性。
我们二分所需要的代价,假设为$len$,那么我们在check的时候,如果代价最多为$len$,意味着所有的操作指令一定在长度为$len$的区间内的,因此我们需要枚举序列中所有长度为$len$的区间。在枚举每一个长度为$len$的区间时,我们需要快速判断如果只修改这个区间内的指令,能否让机器人走到终点,这个时间复杂度应该是$O \left( 1 \right)$。
我们可以把整个序列分成三段:
机器人每次都有上下左右四个方向的向量之一,如果要走到的最终位置,就是每一次指令对应的向量的和。其中,左右为同一个向量维度(水平方向),向左就减$1$,向右就加$1$。上下为同一个维度(竖直方向),向上就加$1$,向下就减$1$。
能不能到终点其实就是算这三段的向量和(分别算水平方向与竖直方向的)。由于我们只改变长度为$len$的这一段,另外两段是不会改变的,因此$s_{1} + s_{3}$是一个定值。然后长度为$len$的区间每一个位置都可以设置为任意的指令,因此$s_{2}$是一个变量。因此$s_{1} + s_{2} + s_{3}$得到的值应该是一个区间范围,我们只需要判断在这个区间范围内,是否包含到终点的值。
要求某部分区间的和,可以用前缀和。不过这里需要开两个前缀和数组,分别求水平方向和竖直方向的前缀和。
由于$s_{1} + s_{3}$是定值,因此我们先从起点根据这个和走到某一个点$\left( {x_{1}, y_{1}} \right)$。假设终点是$\left( {x_{2}, y_{2}} \right)$,我们要从$\left( {x_{1}, y_{1}} \right)$走到$\left( {x_{2}, y_{2}} \right)$,只能借助长度为$len$这个区间的指令。因此我们要判断的是从$\left( {x_{1}, y_{1}} \right)$能否恰好走$len$步,走到$\left( {x_{2}, y_{2}} \right)$。
由于求的是曼哈顿距离,因此要从$\left( {x_{1}, y_{1}} \right)$到$\left( {x_{2}, y_{2}} \right)$的曼哈顿距离为$\left| {x_{2} - x_{1}} \right| + \left| {y_{2} - y_{1}} \right|$,即至少需要走$\left| {x_{2} - x_{1}} \right| + \left| {y_{2} - y_{1}} \right|$步。因为每走一步最多让这两点的距离减$1$,要让距离变成$0$,因此$len$要满足$len \geq \left| {x_{2} - x_{1}} \right| + \left| {y_{2} - y_{1}} \right|$。因此我们可以构造出一条路径,使得恰好走$\left| {x_{2} - x_{1}} \right| + \left| {y_{2} - y_{1}} \right|$步,从$\left( {x_{1}, y_{1}} \right)$走到$\left( {x_{2}, y_{2}} \right)$。对于剩余的步数$len - \left| {x_{2} - x_{1}} \right| - \left| {y_{2} - y_{1}} \right|$,这个值应该是偶数,因为此时$\left( {x_{1}, y_{1}} \right)$到$\left( {x_{2}, y_{2}} \right)$的距离为$0$,如果是奇数,那么必然会使$\left( {x_{1}, y_{1}} \right)$到$\left( {x_{2}, y_{2}} \right)$的距离变成$1$或$-1$。偶数的话可以构造出$1$和$-1$的情况,使得距离恰好抵消。
因此判断能否通过这个长度$len$的区间,使得$\left( {x_{1}, y_{1}} \right)$走到$\left( {x_{2}, y_{2}} \right)$,要满足两个条件:
- $len \geq \left| {x_{2} - x_{1}} \right| + \left| {y_{2} - y_{1}} \right|$
- $2 \mid \left( len - \left| {x_{2} - x_{1}} \right| + \left| {y_{2} - y_{1}} \right| \right)$
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