CF538G Berserk Robot 题解

Description

有一个机器人,第 00 秒时在 (0,0)(0,0) 位置。

机器人会循环执行一个长度为 ll 的指令序列,每秒执行一个指令。

指令有 ULDR 四种,分别代表向上/左/下/右移动一格。

你不知道这个指令序列具体是什么,但是你知道 nn 条信息,第 ii 条信息为「第 tit_i 秒时机器人在 (xi,yi)(x_i,y_i)」,保证 tt 递增。

你需要构造一个满足这些信息的指令序列,或判断不存在。

n2×105n \le 2 \times 10^5l2×106l \le 2 \times 10^6ti,xi,yi1018t_i,|x_i|,|y_i| \le 10^{18}

Solution

注意到这里每次移动 x,yx,y 会互相影响,而不是独立的,考虑把原图转 4545^{\circ} 即点 (x,y)(x,y) 变为 (x+y,xy)(x+y,x-y),这样操作就变为 (1,1),(1,1),(1,1),(1,1)(1,1),(1,-1),(-1,1),(-1,-1)

这样已经可以做了,但 1,11,-1 这类操作不够优美,考虑让 (x,y)(x,y) 变为 (y+x+t2,yx+t2)\left(\frac{y+x+t}{2},\frac{y-x+t}{2}\right),操作就只有 (1,1),(1,0),(0,1),(0,0)(1,1),(1,0),(0,1),(0,0),这样题目就简化很多了。

先考虑 xx 的情况,对于 yy 同理。

不妨设 sis_i 表示前 ii 个指令对 xx 的贡献值,对于一组信息 (ti,xi)(t_i,x_i)ri=timodl,ki=tilr_i=t_i\bmod l,k_i=\left\lfloor\frac{t_i}{l}\right\rfloor,一定满足 xi=sri+kislx_i=s_{r_i}+k_is_l,所以sri=xikisls_{r_i}=x_i-k_is_l

考虑按照 rir_i 排序,容易发现按照 rr[1,l][1,l] 分成若干块,对于块内的操作可以随便排序,所以 0(xi+1ki+1sl)(xikisl)ri+1ri0\leq (x_{i+1}-k_{i+1}s_l)-(x_{i}-k_is_l)\leq r_{i+1}-r_{i},这里为了让 [1,r1][1,r_1][rn+1,l][r_n+1,l] 这两个块也考虑到,可以加入 k=0,r=0,x=0k=0,r=0,x=0k=1,r=l,x=0k=-1,r=l,x=0 这两组信息。

通过解不等式就可以得到 sls_l 的范围,然后随便取一个 sls_l 的可能取值对于每个块分别考虑就可以构造出答案了。

时间复杂度:O(nlogn+l)O(n\log n+l)

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <bits/stdc++.h>

#define int int64_t

const int kMaxN = 2e5 + 5, kMaxL = 2e6 + 5;

int n, l;
bool ans[kMaxL][2];
std::tuple<int, int, int, int> a[kMaxN];

char getch(bool o1, bool o2) {
if (!o1 && !o2) return 'D';
else if (!o1 && o2) return 'L';
else if (o1 && !o2) return 'R';
else return 'U';
}

int cei(int x, int k) {
if (k < 0) x = -x, k = -k;
if (x >= 0) return (x + k - 1) / k;
else return -((-x) / k);
// return ceil((long double)x / k);
}

int flr(int x, int k) {
if (k < 0) x = -x, k = -k;
if (x >= 0) return x / k;
else return -((-x + k - 1) / k);
// return floor((long double)x / k);
}

void dickdreamer() {
std::cin >> n >> l;
for (int i = 1; i <= n; ++i) {
int t, x, y;
std::cin >> t >> x >> y;
if ((x + y - t) & 1) return void(std::cout << "NO\n");
a[i] = {t % l, t / l, (y + x + t) / 2, (y - x + t) / 2};
}
a[++n] = {0, 0, 0, 0}, a[++n] = {l, -1, 0, 0};
std::sort(a + 1, a + 1 + n);
int L = 0, R = l;
for (int i = 1; i < n; ++i) {
int k = std::get<1>(a[i]) - std::get<1>(a[i + 1]);
int nl = std::get<2>(a[i]) - std::get<2>(a[i + 1]);
int nr = nl + std::get<0>(a[i + 1]) - std::get<0>(a[i]);
assert(nl <= nr);
if (!k && (nl > 0 || nr < 0)) return void(std::cout << "NO\n");
if (k > 0)
L = std::max(L, cei(nl, k)), R = std::min(R, flr(nr, k));
else if (k < 0)
L = std::max(L, cei(nr, k)), R = std::min(R, flr(nl, k));
}
if (L > R) return void(std::cout << "NO\n");
for (int i = 1; i < n; ++i) {
int det = (std::get<2>(a[i + 1]) - L * std::get<1>(a[i + 1])) -
(std::get<2>(a[i]) - L * std::get<1>(a[i]));
assert(det >= 0);
int nl = std::get<0>(a[i]) + 1, nr = std::get<0>(a[i]) + det;
for (int j = nl; j <= nr; ++j) ans[j][0] = 1;
}
L = 0, R = l;
for (int i = 1; i < n; ++i) {
int k = std::get<1>(a[i]) - std::get<1>(a[i + 1]);
int nl = std::get<3>(a[i]) - std::get<3>(a[i + 1]);
int nr = nl + std::get<0>(a[i + 1]) - std::get<0>(a[i]);
assert(nl <= nr);
if (!k && (nl > 0 || nr < 0)) return void(std::cout << "NO\n");
if (k > 0)
L = std::max(L, cei(nl, k)), R = std::min(R, flr(nr, k));
else if (k < 0)
L = std::max(L, cei(nr, k)), R = std::min(R, flr(nl, k));
}
if (L > R) return void(std::cout << "NO\n");
for (int i = 1; i < n; ++i) {
int det = (std::get<3>(a[i + 1]) - L * std::get<1>(a[i + 1])) -
(std::get<3>(a[i]) - L * std::get<1>(a[i]));
assert(det >= 0);
int nl = std::get<0>(a[i]) + 1, nr = std::get<0>(a[i]) + det;
for (int j = nl; j <= nr; ++j) ans[j][1] = 1;
}

for (int i = 1; i <= l; ++i) std::cout << getch(ans[i][0], ans[i][1]);
}

int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
// std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

CF538G Berserk Robot 题解
https://sobaliuziao.github.io/2024/07/29/post/805ce7ff.html
作者
Egg_laying_master
发布于
2024年7月29日
许可协议