May 8, 2020
https://atcoder.jp/contests/abc089/tasks/abc089_d
解説と別方針で解いたのでメモ。
1個先のマスに移動したときのコストはで計算できるので、N個先に移動したときのコストはダブリングを使ってで計算できる。
#define MAX_H 300 #define MAX_W 300 #define LOG_N 20 using P = pair<i64, i64>; P C[LOG_N + 1][MAX_H * MAX_W + 10]; int main() { i64 H, W, D; cin >> H >> W >> D; i64 N = H * W + 1; vector<P> Num(N); REP(y, H) { REP(x, W) { i64 a; cin >> a; Num[a] = P(y, x); } } auto cost = [](const P &p1, const P &p2) { return abs(p1.first - p2.first) + abs(p1.second - p2.second); }; REPS(i, N) { if (i + D >= N) { C[0][i] = mp(-1, -1); continue; } C[0][i] = mp(i + D, cost(Num[i], Num[i + D])); } REP(k, LOG_N) { REPS(i, N) { if (C[k][i].first == -1) C[k + 1][i] = mp(-1, -1); else { C[k + 1][i] = mp(C[k][C[k][i].first].first, C[k][i].second + C[k][C[k][i].first].second); } } } i64 Q; cin >> Q; while(Q--) { i64 l, r; cin >> l >> r; i64 n = (r - l) / D; i64 cur = l; i64 s = 0; REP(k, LOG_N) { if (cur == -1) break; if ((n >> k) & 1) { s += C[k][cur].second; cur = C[k][cur].first; } } cout << s << endl; } return 0; }