<-- home

AtCoder ABC089 D

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;
}