Description
有一个机器人,第 0 秒时在 (0,0) 位置。
机器人会循环执行一个长度为 l 的指令序列,每秒执行一个指令。
指令有 ULDR 四种,分别代表向上/左/下/右移动一格。
你不知道这个指令序列具体是什么,但是你知道 n 条信息,第 i 条信息为「第 ti 秒时机器人在 (xi,yi)」,保证 t 递增。
你需要构造一个满足这些信息的指令序列,或判断不存在。
n≤2×105,l≤2×106,ti,∣xi∣,∣yi∣≤1018。
Solution
注意到这里每次移动 x,y 会互相影响,而不是独立的,考虑把原图转 45∘ 即点 (x,y) 变为 (x+y,x−y),这样操作就变为 (1,1),(1,−1),(−1,1),(−1,−1)。
这样已经可以做了,但 1,−1 这类操作不够优美,考虑让 (x,y) 变为 (2y+x+t,2y−x+t),操作就只有 (1,1),(1,0),(0,1),(0,0),这样题目就简化很多了。
先考虑 x 的情况,对于 y 同理。
不妨设 si 表示前 i 个指令对 x 的贡献值,对于一组信息 (ti,xi),ri=timodl,ki=⌊lti⌋,一定满足 xi=sri+kisl,所以sri=xi−kisl。
考虑按照 ri 排序,容易发现按照 r 把 [1,l] 分成若干块,对于块内的操作可以随便排序,所以 0≤(xi+1−ki+1sl)−(xi−kisl)≤ri+1−ri,这里为了让 [1,r1] 和 [rn+1,l] 这两个块也考虑到,可以加入 k=0,r=0,x=0 和 k=−1,r=l,x=0 这两组信息。
通过解不等式就可以得到 sl 的范围,然后随便取一个 sl 的可能取值对于每个块分别考虑就可以构造出答案了。
时间复杂度:O(nlogn+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); }
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); }
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; while (T--) dickdreamer(); return 0; }
|