SRM435 Div2 1000

問題

野鳥が全部でbNいる.一日のはじめにcPDだけ捕まえて調査し夜には放す.調査では鳥の足にマークをつける(すでについてたらそのまま放す).dN日繰り返したあとで,マークが付いている鳥の数がbMである確率を求める.

考え方

dpかdfs.
dp[日][マークの付いた鳥の数]でやった.ある日(day),捕まえた鳥のうちマークが付いた鳥の数がmだった場合,組み合わせCombを使って,
prob = Comb(マークの付いた鳥から(cPD-j)鳥だけ選ぶ)*Comb(マークがついてない鳥からj鳥だけ選ぶ)/Comb(bN鳥からcPD鳥だけ選ぶ);
dp[day+1][m+j] += dp[day][m] * prob;
と書ける.
(鳥は識別できないので,マークの有無でしか確認できない=>2^20通りではなく20通りで十分.各時点から組み合わせの分だけ分岐するのでそれを確率probとすると次の日の確率はその状態での確率*probになる)
以下,破滅的なコード.

int Comb(int n, int k){
  if(n==0 || k==0) return 1;
  int f[n+1][n+1]; for(int i=0; i<n+1; i++) f[0][i] = f[i][0] = 1;
  for(int i=1; i<n+1; i++) for(int j=1; j<n+1; j++){
    f[i][j] = f[i-1][j]+f[i][j-1];
    if(i+j==n && j==k) return f[i][j];
  }
  return 1;
}

double dp[6][21];

double solve(int bN, int cPD, int dN, int bM){
  rep(i,6) rep(j,21) dp[i][j] = 0.0; 
  dp[0][0] = 1.0;
  rep(d,dN) rep(i,bN+1){
    rep(j,bN-i+1){
      if(0<=cPD-j && cPD-j<=i && 0<=j && j<=bN-i){
	double prob = Comb(i,cPD-j) * Comb(bN-i, j) / (double)Comb(bN, cPD);
	dp[d+1][i+j] += dp[d][i] * prob;
      }
    }
  }
  return dp[dN][bM];
}

class BirdsCounting {
  public:
  double computeProbability(int birdsNumber, int caughtPerDay, int daysNumber, int birdsMarked) {
    return solve(birdsNumber, caughtPerDay, daysNumber, birdsMarked);
  }
};

反省

問題をきちんと読む.マークが付いていたらマークを外すと誤読:-(