ABC 089
Table of Contents
https://atcoder.jp/contests/abc089
A. Grouping 2
https://atcoder.jp/contests/abc089/tasks/abc089_a
B. Hina Arare
https://atcoder.jp/contests/abc089/tasks/abc089_b
C. March
https://atcoder.jp/contests/abc089/tasks/abc089_c
D. Practical Skill Test
https://atcoder.jp/contests/abc089/tasks/abc089_d
自力 AC
考えたこと
- $D$ が固定だから経路がかぶるものが出てきそう
- $R_i$ を $D$ で割った余りが $k$ となる $R_i$ の集合を $G_{k}$ とする
- $G_{k}$ の中から最大の $R_{\max}$ を選ぶ
- $L$ から $R$ までの移動で使う魔力の総和を $f(L, R)$ とする
- $f(R_{\max}, R_{\max})$, $f(R_{\max} - D, R_{\max})$, … を求める
- $f(L, R) = f(L, R_{\max}) - f(R, R_{\max})$
- 累積和で求められそう
解法
「考えたこと」に従った実装したもの。$R_{\max}$ から下っていくことはできるけれど、最小の $L$ の出発点を考えると面倒そうに思えてこの実装になった。
void solve() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
ll H, W, D;
cin >> H >> W >> D;
vector A(H, vll(W));
rep(i, H) rep(j, W) {
cin >> A[i][j];
A[i][j]--;
}
vector<pair<int, int>> num_pos(H * W);
rep(i, H) rep(j, W) num_pos[A[i][j]] = {i, j};
int Q;
cin >> Q;
vector<pair<int, int>> queries;
rep(i, Q) {
int l, r;
cin >> l >> r;
l--, r--;
queries.emplace_back(l, r);
}
vint rmax(D, 0);
vector<bool> rexists(D, 0);
for (auto [l, r] : queries) {
chmax(rmax[r % D], r);
rexists[r % D] = true;
}
map<pair<int, int>, ll> memo;
auto f = [&](auto f, int l, int r) -> ll {
if (l == r)
return 0;
auto [ni, nj] = num_pos[l + D];
auto [i, j] = num_pos[l];
return memo[{l, r}] = abs(ni - i) + abs(nj - j) + f(f, l + D, r);
};
rep(i, D) {
if (!rexists[i])
continue;
f(f, i, rmax[i]);
}
for (auto [l, r] : queries) {
int rmx = rmax[r % D];
cout << memo[{l, rmx}] - memo[{r, rmx}] << '\n';
}
}
解説見て直した実装。最小の $L$ は単純に $0 \sim D-1$ 出発で考えればいいだけだった。
void solve() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
ll H, W, D;
cin >> H >> W >> D;
vector A(H, vll(W));
rep(i, H) rep(j, W) {
cin >> A[i][j];
A[i][j]--;
}
vector<pair<int, int>> num_pos(H * W);
rep(i, H) rep(j, W) num_pos[A[i][j]] = {i, j};
vll cumsum(H * W);
rep2(d, D, H * W) {
auto [ni, nj] = num_pos[d];
auto [i, j] = num_pos[d - D];
cumsum[d] = cumsum[d - D] + abs(ni - i) + abs(nj - j);
}
int Q;
cin >> Q;
rep(_, Q) {
int l, r;
cin >> l >> r;
l--, r--;
cout << cumsum[r] - cumsum[l] << endl;
}
}