SRM460 Div1 Medium(500) TheFansAndMeetingsDivOne
まず、JohnとBrusのそれぞれがl人のファンに会う確率を動的計画法で求める。Johnがi番目までの街の中からj個の街を訪れてl人のファンに会う確率をpJi,j,lとすると、
pJi,0,0 = 1
pJi,0,l = 0 (l>0)
pJi,j,l = Σ[m=minJ[i-1],maxJ[i-1] ] pJi-1,j-1,l-m s + pJi-1,j,l(1-s)。
ここで、sはj番目の街を訪れる確率で、s=j/i。
ファンの人数が一致する確率は、pJn,k・pBn,k。
#include <vector> #include <numeric> using namespace std; class TheFansAndMeetingsDivOne { vector<double> fan( vector<int> minf, vector<int> maxf, int k ); public: double find( vector <int> minJ, vector <int> maxJ, vector <int> minB, vector <int> maxB, int k ); }; double TheFansAndMeetingsDivOne::find( vector <int> minJ, vector <int> maxJ, vector <int> minB, vector <int> maxB, int k ) { vector<double> pJ = fan( minJ, maxJ, k ); vector<double> pB = fan( minB, maxB, k ); int m = (int)min( pJ.size(), pB.size() ); return inner_product( pJ.begin(), pJ.begin()+m, pB.begin(), 0.0 ); } // k個の街を訪れてi人のファンに会う確率の配列を返す vector<double> TheFansAndMeetingsDivOne::fan( vector<int> minf, vector<int> maxf, int k ) { int n = (int)minf.size(); int lm = accumulate( maxf.begin(), maxf.end(), 0 ); // [i][j][l] i番目までの街のうちj個の街に訪れてl人のファンに会う確率 static double p[41][41][40*40+1]; for ( int i=0; i<=n; i++ ) for ( int j=0; j<=i; j++ ) for ( int l=0; l<=lm; l++ ) { if ( j == 0 ) { p[i][j][l] = l==0 ? 1 : 0; } else { double s = (double)j / i; // j番目の街を訪れる確率 double *f = p[i-1][j-1] + max( l-maxf[i-1], 0 ); double *t = p[i-1][j-1] + max( l-minf[i-1]+1, 0 ); p[i][j][l] = accumulate(f,t,0.0) / (maxf[i-1]-minf[i-1]+1) * s + p[i-1][j][l] * (1-s); } } return vector<double>( p[n][k], p[n][k]+lm+1 ); }