机器人移动

机器人移动

在一个无限大的二维平面上有一个机器人。

初始时,机器人位于点 $\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$ 的字符串,表示指令序列,字符串中只包含 UDL ,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)$,要满足两个条件:

  1. $len \geq \left| {x_{2} - x_{1}} \right| + \left| {y_{2} - y_{1}} \right|$
  2. $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/

posted @ 2022-04-01 20:31  onlyblues  阅读(291)  评论(0编辑  收藏  举报
Web Analytics