B - Number Box Editorial by SSRS


公式解説の時間計算量は \(\Theta(N^3)\) ですが、時間計算量 \(\Theta(N^2)\) の解法が存在します。(ABC F~G 程度の難易度です)

動く方向を固定します。簡単のため、右方向への移動の場合を説明します。(他の方向でも同様です。)

開始位置の行を固定し、その行の数字を順に並べた文字列を \(S\) とすると、その行のマスから開始して得られる文字列は \(S\) を rotate したものです。よって、以下の問題に帰着します。

\(N\) 文字の文字列 \(S\) がある。\(S\) を rotate したもののうち辞書順で最大のものを求めよ。

\(S\)\(2\) つ連結させた文字列を \(T\) とおくと、\(T\) の最初の \(N\) 個の suffix のうち辞書順で最大のものを求めればよいです。\(T\) の suffix array のうち \(N\) 未満の数で最も右に出現するものが rotate でずらす量となります。

C++ の実装例 https://atcoder.jp/contests/abc258/submissions/32939952

#include <bits/stdc++.h>
#include <atcoder/string>
using namespace std;
vector<int> dx = {1, 0, -1, 0, 1, 1, -1, -1};
vector<int> dy = {0, 1, 0, -1, 1, -1, 1, -1};
int main(){
  int N;
  cin >> N;
  vector<vector<char>> A(N, vector<char>(N));
  for (int i = 0; i < N; i++){
    for (int j = 0; j < N; j++){
      cin >> A[i][j];
    }
  }
  string ans;
  for (int i = 0; i < N; i++){
    for (int j = 0; j < 8; j++){
      int x = i, y = 0;
      if (j == 0 || j == 2){
        swap(x, y);
      }
      string S;
      for (int k = 0; k < N; k++){
        S += A[x][y];
        x += dx[j];
        y += dy[j];
        x = (x + N) % N;
        y = (y + N) % N;
      }
      string T = S + S;
      vector<int> sa = atcoder::suffix_array(T);
      int p = 0;
      for (int k = 0; k < N * 2; k++){
        if (sa[k] < N){
          p = sa[k];
        }
      }
      rotate(S.begin(), S.begin() + p, S.end());
      ans = max(ans, S);
    }
  }
  cout << ans << endl;
}

posted:
last update: