Official

E - 暗号変換装置とパスワード認証 / Cipher Conversion Device and Password Authentication Editorial by physics0523


ひとまず、 \(B_i=0\) なる \(B_i\)\(1\) とした暗号は、少なくとも \(0\) 人の認証が成功する辞書順最小のパスワードなので、それを暫定的な解とします。

エージェントの順番を \(N!\) 通り全て試すことを考えます。
エージェントの順番を固定した際、そのエージェントが見るパスワードが受ける変換を求めることができます。
この変換から、各エージェントが「正しい」とみなす元のパスワードを復元することができます。 このとき、元のパスワードに対して何人が正しいとみなすかも求めておくことができます。
このパスワードと \(B\) とを比較して、元のパスワードがありえるものであれば、問題文の基準に照らして「正しいとみなすエージェントの多い順」、同じであれば「辞書順最小」を採用することでこの問題に正解できます。

実装例 (C++):

#include<bits/stdc++.h>

using namespace std;

int main(){
  int N,K,L;
  cin >> N >> K >> L;
  vector<int> B(L);
  for(auto &nx : B){ cin >> nx; }
  vector<vector<int>> T(N,vector<int>(L));
  vector<vector<int>> A(N,vector<int>(K+1));
  for(int i=0;i<N;i++){
    for(int j=0;j<L;j++){cin >> T[i][j];}
    for(int j=1;j<=K;j++){cin >> A[i][j];}
  }

  int rn=0;
  vector<int> rp=B;
  for(auto &nx : rp){
    if(nx==0){nx=1;}
  }

  vector<int> agt;
  for(int i=0;i<N;i++){agt.push_back(i);}
  do{
    vector<int> C(K+1);
    for(int i=1;i<=K;i++){C[i]=i;}
    map<vector<int>,int> mp;
    for(auto &nx : agt){
      vector<int> inv(K+1);
      for(int i=1;i<=K;i++){ inv[C[i]]=i; }

      vector<int> org(L);
      for(int i=0;i<L;i++){
        org[i]=inv[T[nx][i]];
      }
      mp[org]++;

      vector<int> nC(K+1);
      for(int i=1;i<=K;i++){ nC[i]=A[nx][C[i]]; }
      C=nC;
    }
    for(auto &nx : mp){
      bool ok=true;
      for(int i=0;i<L;i++){
        if(B[i]!=0 && B[i]!=nx.first[i]){ok=false; break;}
      }
      if(!ok){continue;}
      if(rn<nx.second){
        rn=nx.second;
        rp=nx.first;
      }
      else if(rn==nx.second){
        rp=min(rp,nx.first);
      }
    }
  }while(next_permutation(agt.begin(),agt.end()));

  cout << rn << "\n";
  for(int i=0;i<L;i++){
    if(i){cout << " ";}
    cout << rp[i];
  }cout << "\n";
  return 0;
}

posted:
last update: