I - Hands on Ring (Hard) Editorial by en_translator
Consider solving this problem with Dynamic Programming (DP). After completing up to instruction \(i\), hand \(H_i\) is known to be holding part \(T_i\), while the other is unknown; this allows us to define the DP as follows:
\(\mathrm{dp}_{i,j}:=\) the minimum total number of operations to complete up to instruction \(i\), with the hand other than \(H_i\) ends up being at part \(j\).
Now let us consider the transitions. Suppose that the current position of the left and right hands are parts \(l\) and \(r\), respectively, and you want to move your left hand to part \(l'\). While there seems to be many patterns, as you can move any hand, but in fact there are only the following two kinds of move that may be optimal:
- Move your left hand without moving your right hand (as in problem B), only if \(l'\neq r\).
- Move your left hand in the other direction than 1. To avoid collision with your right hand, also move your right hand minimum possible times along with the left hand. Specifically, if you are moving your left hand as parts \(l\rightarrow l+1\rightarrow \dots\rightarrow l'\), move your right hand as parts \(r\rightarrow r+1\rightarrow \dots\rightarrow l'+1\); if the left hand goes \(l\rightarrow l-1\rightarrow \dots\rightarrow l'\), move the right hand as \(r\rightarrow r-1\rightarrow \dots\rightarrow l'-1\). (Here, parts \((N+1)\) refers to part \(1\), and \(0\) to \(N\).)
Now the transition costs only \(O(1)\) time, enabling us to solve the problem in a total of \(O(NQ)\) time. Carefully implement the case division and handle the process on the circular topology.
Sample code (C++):
#include <bits/stdc++.h>
using namespace std;
const int inf = 1e9;
vector<pair<int, int>> num_move(int n, int from, int to, int ng) {
vector<pair<int, int>> res;
if (to != ng) {
if (min(from, to) < ng and ng < max(from, to)) {
res.emplace_back(n - abs(from - to), ng);
} else {
res.emplace_back(abs(from - to), ng);
}
}
if (from < ng) {
if (from < to and to <= ng) {
res.emplace_back(n - (to - from) + (ng - to + 1), to - 1);
}
if (to < from or ng <= to) {
res.emplace_back((to - from + n) % n + (to - ng + n) % n + 1, (to + 1) % n);
}
} else {
if (ng <= to and to < from) {
res.emplace_back(n - (from - to) + (to - ng + 1), to + 1);
}
if (to <= ng or from < to) {
res.emplace_back((from - to + n) % n + (ng - to + n) % n + 1, (to - 1 + n) % n);
}
}
return res;
}
int main() {
int n, q;
cin >> n >> q;
vector dp(q + 1, vector<int>(n, inf));
int ph = 0, pt = 0;
dp[0][1] = 0;
for (int i = 0; i < q; i++) {
char hc;
int t;
cin >> hc >> t;
--t;
int h = (hc == 'L' ? 0 : 1);
for (int j = 0; j < n; j++) {
if (dp[i][j] == inf) continue;
vector<int> pos(2);
pos[ph] = pt;
pos[ph ^ 1] = j;
for (auto [num, npos]: num_move(n, pos[h], t, pos[h ^ 1])) {
dp[i + 1][npos] = min(dp[i + 1][npos], dp[i][j] + num);
}
}
ph = h, pt = t;
}
int ans = inf;
for (int i = 0; i < n; i++) ans = min(ans, dp[q][i]);
cout << ans << endl;
}
posted:
last update: