結果
問題 | No.3121 Prime Dance |
ユーザー |
|
提出日時 | 2025-04-17 11:37:48 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 543 ms / 2,000 ms |
コード長 | 3,869 bytes |
コンパイル時間 | 4,049 ms |
コンパイル使用メモリ | 291,668 KB |
実行使用メモリ | 146,944 KB |
最終ジャッジ日時 | 2025-04-17 11:37:59 |
合計ジャッジ時間 | 9,921 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 2 |
other | AC * 21 |
ソースコード
#include<bits/stdc++.h> using namespace std; #define rep(i, a, b) for(int i = a; i < (b); i++) const int inf = 1e9; int main(){ int h, w; cin >> h >> w; int sx, sy; cin >> sx >> sy; sx--; sy--; int gx, gy; cin >> gx >> gy; gx--; gy--; vector<string> s(h); rep(i, 0, h) cin >> s[i]; // 左右移動が可能なマスかどうか vector<vector<int>> is_side(h, vector<int>(w, 0)); rep(i, 0, h) rep(j, 0, w) { if(s[i][j] == '#') continue; if(j > 0 && s[i][j-1] != '#') is_side[i][j] = 1; if(j < w - 1 && s[i][j+1] != '#') is_side[i][j] = 1; } // dp[i][j][k][l] := (i,j)に下に移動をk回行った時の到達するのに必要な左移動のコスト(lは左右移動が可能なマスを通ったか?) vector dp(h, vector(w, vector(h * w, vector<int>(2, inf)))); dp[sx][sy][0][0] = 0; deque<array<int, 4>> que; que.push_back({sx, sy, 0, 0}); while(que.size()) { auto [x, y, k, l] = que.front(); que.pop_front(); // 下に移動 if(x + 1 < h && s[x + 1][y] != '#' && k + 1 < h * w) { int nx = x + 1; if(dp[nx][y][k+1][l | is_side[nx][y]] > dp[x][y][k][l]) { dp[nx][y][k+1][l | is_side[nx][y]] = dp[x][y][k][l]; que.push_front({nx, y, k + 1, l | is_side[nx][y]}); } } // 上に移動 if(x - 1 >= 0 && s[x - 1][y] != '#') { int nx = x - 1; if(dp[nx][y][k][l | is_side[nx][y]] > dp[x][y][k][l]) { dp[nx][y][k][l | is_side[nx][y]] = dp[x][y][k][l]; que.push_front({nx, y, k, l | is_side[nx][y]}); } } // 右に移動 if(y + 1 < w && s[x][y + 1] != '#') { int ny = y + 1; if(dp[x][ny][k][l | is_side[x][ny]] > dp[x][y][k][l] + 1) { dp[x][ny][k][l | is_side[x][ny]] = dp[x][y][k][l] + 1; que.push_back({x, ny, k, l | is_side[x][ny]}); } } // 左に移動 if(y - 1 >= 0 && s[x][y - 1] != '#') { int ny = y - 1; if(dp[x][ny][k][l | is_side[x][ny]] > dp[x][y][k][l]) { dp[x][ny][k][l | is_side[x][ny]] = dp[x][y][k][l]; que.push_front({x, ny, k, l | is_side[x][ny]}); } } } // primes (最大値はこれで良い?) vector<int> is_prime(h * w * 4, 1); is_prime[0] = 0; is_prime[1] = 0; rep(i, 2, h * w * 4) { if(is_prime[i]) { for(int j = i * 2; j < h * w * 4; j += i) { is_prime[j] = 0; } } } auto calc = [&is_prime](int a, int b) { // a + i, b + i が両方とも素数になるような最小のiを求め a + b + 2 * iを返す // 存在しない場合はinfを返す if(a > b) swap(a, b); if((b - a) % 2 == 1) { if(a > 2) return inf; b += 2 - a; a = 2; if(is_prime[b] && is_prime[a]) return a + b; else return inf; } else{ int i = 0; while(!is_prime[a+i] || !is_prime[b+i]) { i++; } return a + b + 2 * i; } }; // 答えを求める int ans = inf; rep(k, 0, h * w) { if(dp[gx][gy][k][1] == inf) continue; // 下向き移動がkの時のそれぞれのmin int down = k; int up = down + (sx - gx); int right = dp[gx][gy][k][1]; int left = right + (sy - gy); if(down == 0 && up == 0) continue; // 上下移動可能なマスを通っていないケース int res = calc(down, up) + calc(right, left); ans = min(ans, res); } if(ans == inf) cout << -1 << endl; else cout << ans << endl; }