Official

C - RANDOM Editorial by physics0523


今回の問題は、以下の \(2\) つの手順に分けて解くことができます。

A. 各列の情報を取り扱いやすい形にする
B. \(S\) の列を並べ替えて \(T\) と等しくできるか判定する

A. について、\(S,T\) それぞれについて行と列を転置して「各列を表現した文字列」の配列に変換すると取り扱いやすいです。

転置とは、2次元配列 \(A\) が与えられた時に \(B[i][j]=A[j][i]\) を満たす \(B\) を作って行と列の情報を置き換えることを指します。具体的な実装方法は実装例を参照して下さい。

転置した後の \(S,T\)\(^tS,^tT\) と表すと、解くべき問題 B. も言い換えられて、 \(^tS\) の行を並べ替えて \(^tT\) と等しくできるか判定する (つまり、文字列の配列同士を比較して、一方を並べ替えてもう一方が作れるかを判定する) 問題となります。
では、この問題はどう解けば良いでしょうか?

一般に、 \(P\) を並び替えて \(Q\) と等しくできるかどうかという問題を解く最も簡単な方法は、 \(P\)\(Q\) を双方ソートしてその結果が同じになるかを調べる ( 同じになれば可能、そうでなければ不可能 ) というものです。

今回の問題でも、 \(^tS\)\(^tT\) の各行を双方ソートしてその結果が同じになるかを調べればこの問題を解くことができます。

この解法の時間計算量は \(O(HW \log W)\) です。 ( \(W\) 要素のソートがボトルネックであり、一度の比較には時間計算量 \(O(H)\) がかかるため、この計算量となります。)

実装例(C++):

#include<bits/stdc++.h>

using namespace std;

int main(){
  int h,w;
  cin >> h >> w;
  vector<string> s(h),t(h);
  for(auto &nx : s){cin >> nx;}
  for(auto &nx : t){cin >> nx;}

  // A.
  vector<string> Ts(w),Tt(w);
  for(int i=0;i<h;i++){
    for(int j=0;j<w;j++){
      Ts[j].push_back(s[i][j]);
      Tt[j].push_back(t[i][j]);
    }
  }

  // B.
  sort(Ts.begin(),Ts.end());
  sort(Tt.begin(),Tt.end());

  if(Ts==Tt){cout << "Yes\n";}
  else{cout << "No\n";}
  return 0;
}

posted:
last update: