20250903 Codeforces 1101C
Codeforces 1073C
Vasya has got a robot which is situated on an infinite Cartesian plane, initially in the cell \((0, 0)\). Robot can perform the following four kinds of operations:
- U — move from \((x, y)\) to \((x, y + 1)\);
- D — move from \((x, y)\) to \((x, y - 1)\);
- L — move from \((x, y)\) to \((x - 1, y)\);
- R — move from \((x, y)\) to \((x + 1, y)\).
Vasya also has got a sequence of \(n\) operations. Vasya wants to modify this sequence so after performing it the robot will end up in \((x, y)\).
Vasya wants to change the sequence so the length of changed subsegment is minimum possible. This length can be calculated as follows: \(maxID - minID + 1\), where \(maxID\) is the maximum index of a changed operation, and \(minID\) is the minimum index of a changed operation. For example, if Vasya changes RRRRRRR to RLRRLRL, then the operations with indices \(2\), \(5\) and \(7\) are changed, so the length of changed subsegment is \(7 - 2 + 1 = 6\). Another example: if Vasya changes DDDD to DDRD, then the length of changed subsegment is \(1\).
If there are no changes, then the length of changed subsegment is \(0\). Changing an operation means replacing it with some operation (possibly the same); Vasya can't insert new operations into the sequence or remove them.
Help Vasya! Tell him the minimum length of subsegment that he needs to change so that the robot will go from \((0, 0)\) to \((x, y)\), or tell him that it's impossible.
题目标签:前缀思想、滑动窗口、二分答案、1800
题目提到了无解的情况,那么什么时候会无解?
先不考虑最小化的问题,如果我们把所有的操作都改了,还是无法到达,这显然是无解的;
但这样还不够,举一个例子,(0, 0) -> (0, 1)需要一步,我现在有2步要走,这显然是无解的。
根据第一个条件,不难想到判据\(d=|x|+|y|\)(曼哈顿距离)。所以我们的无解条件就是:操作数小于曼哈顿距离并且操作数的奇偶性与曼哈顿距离d的奇偶性一致。
剩下的情况必然有解,因为我可以通过修改所有的操作来找到解。题设的目的是$$min(maxID - minID + 1)$$即是最小化一个窗口的长度。只要在这个窗口内的操作我都可以任意修改。
那么我们会发现,如果长度为\(l=m\)的窗口已经足够了,长度\(l>=m\)也是答案;同理,\(l<m\)的长度不是答案。我们考虑二分答案,最小化这个答案。
这里的关键是check函数怎么写。考虑到所有的操作都要进行,假设现在窗口长度是k,那么我们可以枚举所有可能窗口的右端点i,并且提前完成除了[i - k, i]的所有操作,看现在的位置在哪里,是否能够通过k次位移到达目标位置。
这里的难点是如何知道完成其他操作后在哪个位置。因为操作与顺序无关且可逆,我们可以考虑前缀思想。定义:sum[i]:从(0, 0)进行i次操作后到达的位置,那么根据我们枚举的窗口,我们可以把区间划分成三段。[0, i - k), [i - k, i), [i, n],我们可以预处理出sum[],然后通过\(O(1)\)的时间复杂度,查询三段区间尾部的位置。
剩下的就看代码吧。
#include <bits/stdc++.h>
using u32 = uint32_t;
using i64 = int64_t;
using u64 = uint64_t;
using i128 = __int128;
using u128 = unsigned __int128;
using namespace std;
#define F(i, a, b) for (int i = (a); i <= (b); i++)
#define Fd(i, a, b) for (int i = (a); i >= (b); i--)
#ifndef DEBUG
struct __X {
__X& operator<<(const auto& str) { return *this; }
void sp(const std::string& str = "") {}
} dout;
#define debug(x) ;
#endif
constexpr int mod = 998244353;
constexpr int MOD = 1E9 + 7;
constexpr int INF = 1E9;
constexpr int N = 2E5 + 10;
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, x, y;
string s;
cin >> n >> s >> x >> y;
int d = abs(x) + abs(y); // 曼哈顿距离
// 先判断无解
if (n < d || n % 2 != d % 2) {
cout << -1 << '\n';
return 0;
}
// 初始化 这里也可以用pair
struct Point { int x, y; };
vector<Point> sum(n + 1), dirs(256);
dirs['L'] = {-1, 0};
dirs['R'] = {1, 0};
dirs['D'] = {0, -1};
dirs['U'] = {0, 1};
// 预处理sum数组
for (int i = 0; i < n; i ++) {
char b = s[i];
Point d = dirs[b];
sum[i + 1].x = sum[i].x + d.x;
sum[i + 1].y = sum[i].y + d.y;
}
// check函数
auto check = [&](int mid) -> bool {
// 枚举所有窗口的右端点
for (int i = mid; i <= n; i ++) {
// 进行了其他操作之后的位置是
// 进行了n次操作的位置 - 进行了i次操作的位置 + 进行了i-k次操作的位置
// 这里的mid就是上文的k
int nx = sum[i - mid].x + (sum[n].x - sum[i].x);
int ny = sum[i - mid].y + (sum[n].y - sum[i].y);
// 如果到达目标位置的距离够了 就返回true
if (abs(nx - x) + abs(ny - y) <= mid) {
return true;
}
}
// 找不到 返回false
return false;
};
// 开区间二分 窗口长度范围0~n
int lo = -1, hi = n + 1;
while (lo + 1 < hi) {
int mid = (lo + hi) >> 1;
if (check(mid)) hi = mid;
else lo = mid;
}
cout << hi << '\n';
}
/* By Tangzy
⠄⠄⠄⠄⢠⣿⣿⣿⣿⣿⢻⣿⣿⣿⣿⣿⣿⣿⣿⣯⢻⣿⣿⣿⣿⣆⠄⠄⠄
⠄⠄⣼⢀⣿⣿⣿⣿⣏⡏⠄⠹⣿⣿⣿⣿⣿⣿⣿⣿⣧⢻⣿⣿⣿⣿⡆⠄⠄
⠄⠄⡟⣼⣿⣿⣿⣿⣿⠄⠄⠄⠈⠻⣿⣿⣿⣿⣿⣿⣿⣇⢻⣿⣿⣿⣿⠄⠄
⠄⢰⠃⣿⣿⠿⣿⣿⣿⠄⠄⠄⠄⠄⠄⠙⠿⣿⣿⣿⣿⣿⠄⢿⣿⣿⣿⡄⠄
⠄⢸⢠⣿⣿⣧⡙⣿⣿⡆⠄⠄⠄⠄⠄⠄⠄⠈⠛⢿⣿⣿⡇⠸⣿⡿⣸⡇⠄
⠄⠈⡆⣿⣿⣿⣿⣦⡙⠳⠄⠄⠄⠄⠄⠄⢀⣠⣤⣀⣈⠙⠃⠄⠿⢇⣿⡇⠄
⠄⠄⡇⢿⣿⣿⣿⣿⡇⠄⠄⠄⠄⠄⣠⣶⣿⣿⣿⣿⣿⣿⣷⣆⡀⣼⣿⡇⠄
⠄⠄⢹⡘⣿⣿⣿⢿⣷⡀⠄⢀⣴⣾⣟⠉⠉⠉⠉⣽⣿⣿⣿⣿⠇⢹⣿⠃⠄
⠄⠄⠄⢷⡘⢿⣿⣎⢻⣷⠰⣿⣿⣿⣿⣦⣀⣀⣴⣿⣿⣿⠟⢫⡾⢸⡟⠄.
⠄⠄⠄⠄⠻⣦⡙⠿⣧⠙⢷⠙⠻⠿⢿⡿⠿⠿⠛⠋⠉⠄⠂⠘⠁⠞⠄⠄⠄
⠄⠄⠄⠄⠄⠈⠙⠑⣠⣤⣴⡖⠄⠿⣋⣉⣉⡁⠄⢾⣦⠄⠄⠄⠄⠄⠄⠄⠄
*/

浙公网安备 33010602011771号