Official

B - Takahashi's Secret Editorial by leaf1415


  • 初めに高橋君の秘密を知った友達 \(X\) が友達 \(A_X\) にその秘密を教え、
  • 友達 \(A_X\) はさらに友達 \(A_{A_X}\) に秘密を教え、
  • 友達 \(A_{A_X}\) はさらに友達 \(A_{A_{A_X}}\) に秘密を教え、
  • \(\cdots\)

というように「ある友達が別の友達に秘密を教える」ことが繰り返されることで、高橋君の秘密は知れ渡っていきます。 この繰り返しは「ある友達 \(i\) が友達 \(A_i\) に秘密を教えようとしたが、友達 \(A_i \)はすでに秘密を知っていた」ということが起きるまで続きます。

秘密が伝わっていく上記の過程をシミュレーションすることでこの問題を解きます。
例えば、変数 \(i\) と、友達 \(i\) が高橋君の秘密をすでに知っている (\(true\)) かまだ知らないか (\(false\)) を記録するためのブーリアン型の配列 \(b[\ast]\) を用意し、下記のアルゴリズムを実行することで、秘密が伝わっていく過程をシミュレーションできます。

  1. \(i \leftarrow X\) とし、\(b[\ast]\) の要素をすべて \(false\) で初期化する。
  2. \(b[i] \leftarrow true\)
  3. \(i \leftarrow A_i\)
  4. \(b[i] = true\) なら終了する。そうでなければ2.に戻る。

その後、秘密を知っている友達の数(すなわち \(i = 1, 2, \ldots, N\) のうち \(b[i] = true\) となる \(i\) の個数)を数えて出力すればこの問題に正解できます。

C++言語による実装例を以下に記載します。

#include <iostream>
using namespace std;

int n, x;
int a[100001];
bool b[100001];

int main(void)
{
  cin >> n >> x;
  for(int i = 1; i <= n; i++) cin >> a[i];
  
  int i = x;
  do{
    b[i] = true;
    i = a[i];
  }while(!b[i]);
  
  int ans = 0;
  for(int i = 1; i <= n; i++) if(b[i]) ans++;
  cout << ans << endl;
  
  return 0;
}

posted:
last update: