ちょっと考えるAより、解法がすぐ思いつくBの方が簡単では…。
http://codeforces.com/contest/398/problem/B
問題
NxNのグリッドがあり、そのうちのいくつかがすでに塗られている。
コスト1を払うと、ランダムでどこかのマスが塗られる(1度塗ったマスが再度塗られることもある)。
全ての行に1個以上塗られているマスがあり、かつ全ての列に1個以上塗られているマスがある状態になれば終了する。
終了までにかかるコストの期待値を答えよ。
解法
状態として(塗られていない行の数,塗られていない列の数)を持ち、再帰的に確率を求めていけばよい。
今の状態を(R,C)とすると、コスト1で以下のように遷移する。
- (N-R)(N-C)/(N^2)の確率ですでに塗った行・すでに塗った列が選ばれる。この時状態は変わらない。
- R(N-C)/(N^2)の確率でまだ塗られてない行ですでに塗った列が選ばれる。この時状態(R-1,C)になる。
- (N-R)C/(N^2)の確率ですでに塗った行でまだ塗られてない列が選ばれる。この時状態(R,C-1)になる。
- RC/(N^2)の確率でまだ塗られてない行・列が選ばれる。この時状態(R-1,C-1)になる。
状態はN^2で、各状態からの遷移は高々3つと定数なので、全体の計算量はO(N^2)。
int N,M; double dpdp[2001][2001]; int visr[2001],visc[2001]; double dodo(ll x,ll y) { if(x>y) swap(x,y); if(dpdp[x][y]>=0) return dpdp[x][y]; if(x==0 && y==0) return 0; if(x==0) { dpdp[x][y]=dodo(x,y-1)+N/(double)y; } else { dpdp[x][y]=N*(ll)N+x*(N-y)*dodo(x-1,y)+(N-x)*y*dodo(x,y-1)+x*y*dodo(x-1,y-1); dpdp[x][y]/=(double)(N*(x+y)-x*(ll)y); } return dpdp[x][y]; } void solve() { int f,i,j,k,l,x,y; cin>>N>>M; FOR(i,M) { cin>>x>>y; visr[x-1]=1; visc[y-1]=1; } FOR(x,N+1) FOR(y,N+1) dpdp[x][y]=-1; _P("%.12lf\n",dodo(N-count(visr,visr+N,1),N-count(visc,visc+N,1))); }
まとめ
昔より期待値問題に慣れてきたな。