Top
$N$ 個のものがどこかに隠れています。
$N \times N$ の二次元の表の $G_{i\ j}$ は、 $i$ 番目を見つけることができたときに $j$ 番目の場所が分かるようになるかどうか、を表しています。
それぞれのものを手掛かり無しで見つけることができる確率が与えられます。
入手できた個数の期待値を求めてください。
・$1 \le N \le 50$

これムズい。
G[i][i] が 'Y' か 'N' に統一されてないのは訳分からん。

---
肝は 3 つ。
1. $N$ 個のそれぞれを入手できる確率が分かれば、答えはその和である。
気づけないので、今後は知識として入れておく。
期待値の線形性から明らか、じゃねーよ。

2. 与えられた表から、$i$ 番目を入手できたときに $j$ 番目も連鎖的に入手できるかどうか、という表を作る。
深さ優先をやりたくなるけど、ワーシャルフロイドでもこの目的は達成できる。

3. $i$ 番目を入手できる確率というのは何なのか。
まず、$i$ 番目を入手できない確率を考える。
$i$ 番目を入手できないとは、
「$j$ 番目が入手できたとき連鎖的に $i$ 番目も入手できるのに、$j$ 番目が入手できなかった」あるいは「$j$ 番目を入手できたとしても $i$ 番目は入手できない」
ということが全ての $j$ において発生したのである。なので、この確率をすべて掛け算する。
$i$ 番目を入手できた、というのはその余事象で計算できる。

#include <iostream>
#include <algorithm>
using namespace std;
using i64 = long long;

class TheTips { public: double solve(vector<string> clues, vector<int> probability); };

double TheTips::
solve(vector<string> G, vector<int> probability) {
  int n = G.size();
  // H[i][j] := i を入手できたとき、j が連鎖的に入手できるかどうか
  vector<vector<bool>> H(n, vector<bool>(n, false)); // H[n][n]
  for(int i=0; i<n; ++i) {
    for(int j=0; j<n; ++j) {
      H[i][j] = G[i][j] == 'Y';
    }
    H[i][i] = true;
  }
  for(int k=0; k<n; ++k) {
    for(int i=0; i<n; ++i) {
      for(int j=0; j<n; ++j) {
        if(H[i][k] && H[k][j]) {
          H[i][j] = true;
        }
      }
    }
  }
  vector<double> prob(n);
  for(int i=0; i<n; ++i) { prob[i] = probability[i] / 100.0; }
  double res = 0.0;
  for(int i=0; i<n; ++i) {
    double cant = 1.0; // i を入手できない確率(= H[j][i] であるような全ての j を見つけられなかった確率)
    for(int j=0; j<n; ++j) {
      if(H[j][i]) { // j を入手できたときに i も入手できるのなら、
        cant *= 1.0 - prob[j]; // i を入手できない確率は j を見つけられなかった確率である。
//    } else { // j を入手できても i が入手できないのなら、
//      cant *= 1.0; // i は絶対に入手できない。
      }
    }
    res += 1.0 - cant;
  }
  return res;
}
      

(ΦωΦ)<つづく