[CodeQUEEN 2024 予選 ABC358] G - AtCoder Tour

[Q] G - AtCoder Tour

コンテスト終了時点でFastestCodeでした!
BFSでO(HM)の解法です。難しいことはしてません。

考察
1. KがHMより大きい場合、最大値のマスでひたすら待機をすることになりそう。
2. 毎ターン最大値max_Aを獲得できれば理想解を得られる。これを前提と考えると、
3. A -= max_Aとすれば、マスを損失値として管理できる。
4. BFSで、そのマスに到達するまでの最小損失と最小ターン数をメモする。
5. 解答は、すべてのマスについて、K * max_Aからそのターンに至るまでの損失値を除いたもののうち、最大のもの。

実装

int main()
{
 ll H, W, K;
  cin >> H >> W >> K;
  ll si, sj;
  cin >> si >> sj;
  --si;
  --sj;
  vector<vector<ll>> A(H, vector<ll>(W));

  ll max_a = 0;
  rep(i, H) rep(j, W){
    cin >> A[i][j];
    chmax(max_a, A[i][j]);
  }

  // 基本的にmax_aでK回とどまると考える。損失を計算する
  rep(i, H) rep(j, W){ 
    A[i][j] -= max_a;
  }

  // BFS最大2500ターン
  // dp[i][j] = (i, j)にいるときの最小損失と、その最小ターン数
  vector<vector<ll>> dp(H, vector<ll>(W, -oo));
  vector<vector<ll>> turns(H, vector<ll>(W, 0));

  dp[si][sj] = A[si][sj];
  queue<pll> Q;
  // 初期入れ。最初のマスと、最初に移動するマスだけ独立してdpが埋まる
  rep(d, 4){
    ll ni = si + dy[d];
    ll nj = sj + dx[d];
    if (isn_field(ni, nj, H, W))
      continue;
    dp[ni][nj] = A[ni][nj];
    turns[ni][nj] = 1;
    Q.push({ni, nj});
  }

  ll turn = 1;
  while(!Q.empty()){
    if (turn > K)
      break;
    ++turn;
    ll sz = Q.size();
    while(sz--){
      ll i, j;
      tie(i, j) = Q.front();
      Q.pop();
      rep(k, 4){
        ll ni = i + dy[k];
        ll nj = j + dx[k];
        if (isn_field(ni, nj, H, W))
          continue;
        if (dp[ni][nj] >= dp[i][j] + A[ni][nj])
          continue;
        dp[ni][nj] = dp[i][j] + A[ni][nj];
        turns[ni][nj] = turn;
        Q.push({ni, nj});
      }
    }
  }

  ll ans = 0;
  ll mx = K * max_a; // 理想解
  // すべてのマスについて、そのマスでK回待機した場合のスコアを得る
  rep(i, H) rep(j, W){
    chmax(ans, mx + dp[i][j] + A[i][j] * (K - turns[i][j]));
  }
  cout << ans << endl;
}

https://atcoder.jp/contests/abc358/submissions/54623826


この記事が気に入ったらサポートをしてみませんか?