https://yukicoder.me/problems/no/867
解説
https://yukicoder.me/submissions/370451
まず、やはり気になるのは、制約である。
K2がついているし、かつ、A[i][j]の値がとても小さい。
これはKが増えれば増えるほど、K2による影響が増えていきそう。
なので、あるKを境に計算方法を変えるテクかもという感じ。
問題はKの境目をどのくらいにするかというところだが、これは計算量を考えて、決めよう。
俺は証明ができない。
あと、クエリ毎に始点が決まっているが、最短経路問題ではこれは厄介。
(gx, gy)を始点として、クエリ毎を終点とすれば、単一始点最短経路問題となり扱いやすい。
今後は始点終点を逆にして考えよう。
Kがある境目より小さい場合はどのようなアプローチがあるだろうか。
問題を典型的に考えると、無向グラフでの単一始点最短経路なので、ダイクストラが適用できそう。
Kが固定されていると、O(HWlog(HW))で解ける。
これは最大で3*105くらい。
107くらいを目指せばいいので、この操作は100回くらいならできそう。
Kがある境目より大きい場合は、K2によるコストが支配的になる。
なので、ある頂点に向かうときは、移動回数が少ないほうが最良となる。
(sx,sy)から(gx,gy)へ最小回数で移動する経路のうちA[i][j]の総和の最小値を持っておけば、
K2×移動回数を加えるだけで答えが得られる。
これは事前計算を1回しておけば答えることができる。
こっちは計算コストはそんなにかからない。
よって、Kがある境目より小さい場合が計算量が支配的であるので、なるべくKは大きくすることがいい。
ギリギリが108くらいであるので、300回くらいが限界そう。
境目は300としておこう。これで出すとWAで、800msくらいだった。
境界値1000くらいならいけそう。あれ、WA。通っているケースも増えてないし、TLEもある。
境目は300でいいのか。何かバグってた。
int H, W, gx, gy, A[251][251], Q, X[501010], Y[501010], K[501010]; ll ans[1010101]; vector<int> query[1010101]; int threshold = 300; //--------------------------------------------------------------------------------------------------- ll dst[251][251]; bool vis[251][251]; int idx[251][251]; void _main() { cin >> H >> W >> gy >> gx; gx--; gy--; rep(y, 0, H) rep(x, 0, W) cin >> A[y][x]; cin >> Q; rep(i, 0, Q) cin >> Y[i] >> X[i] >> K[i], X[i]--, Y[i]--; rep(q, 0, Q) query[K[q]].push_back(q); // small pattern rep(k, 1, threshold) { if (query[k].size() == 0) continue; rep(y, 0, H) rep(x, 0, W) dst[y][x] = infl, vis[y][x] = false; min_priority_queue<pair<ll, int>> que; dst[gy][gx] = k * k + A[gy][gx]; que.push({ dst[gy][gx], gy * W + gx }); while (!que.empty()) { auto q = que.top(); que.pop(); ll cst = q.first; int y = q.second / W; int x = q.second % W; if (vis[y][x]) continue; vis[y][x] = true; rep(d, 0, 4) { int xx = x + dx[d]; int yy = y + dy[d]; if (0 <= xx and xx < W and 0 <= yy and yy < H) { if (chmin(dst[yy][xx], cst + A[yy][xx] + k * k)) { que.push({ dst[yy][xx] , yy * W + xx}); } } } } fore(q, query[k]) ans[q] = dst[Y[q]][X[q]]; } queue<pair<int, int>> que; rep(y, 0, H) rep(x, 0, W) dst[y][x] = infl, vis[y][x] = false; que.push({ gx, gy }); dst[gy][gx] = A[gy][gx]; vis[gy][gx] = true; idx[gy][gx] = 0; while (!que.empty()) { int x, y; tie(x, y) = que.front(); que.pop(); rep(d, 0, 4) { int xx = x + dx[d]; int yy = y + dy[d]; if (0 <= xx and xx < W and 0 <= yy and yy < H) { if (!vis[yy][xx]) { que.push({ xx, yy }); vis[yy][xx] = true; idx[yy][xx] = idx[y][x] + 1; } if(idx[y][x] + 1 == idx[yy][xx]) chmin(dst[yy][xx], dst[y][x] + A[yy][xx]); } } } // big pattern rep(k, threshold, 1010101) fore(q, query[k]) { int x = X[q], y = Y[q]; ans[q] = dst[y][x] + 1LL * (abs(y - gy) + abs(x - gx) + 1) * k * k; } rep(i, 0, Q) printf("%lld\n", ans[i]); }