kmjp's blog

競技プログラミング参加記です

yukicoder : No.174 カードゲーム(Hard)

こちらの方が易しく感じました。
http://yukicoder.me/problems/326

問題

基本的にNo.173と同じである。
yukicoder : No.173 カードゲーム(Medium) - kmjp's blog

ただし、答えるのは勝率でなくA君の総取得得点の期待値である。

解法

BitDPを用いて、A君・B君のカードのうち、何番目に小さい番号のカードが何試合目に出されるかを求める。
そこから、A君のx番目のカードがB君のy番目のカードと当たる確率P[x][y]が求められる。

あとはA[x]>B[y]なカードA[x],B[y]に対し、(A[x]+B[y])*P[x][y]の総和を取ればよい。

int N,T;
double P[2],ret;
int A[30],B[30];
double PP[2][1<<21];
double PQ[2][21][21];

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N>>P[0]>>P[1];
	FOR(i,N) cin>>A[i];
	FOR(i,N) cin>>B[i];
	sort(A,A+N);
	sort(B,B+N);
	
	PP[0][0]=PP[1][0]=1;
	FOR(i,N) FOR(x,1<<N) if(__builtin_popcount(x)==i) {
		int f=1;
		FOR(j,N) if((x & (1<<j))==0) {
			if(i==N-1) {
				PP[0][x | (1<<j)] += PP[0][x];
				PP[1][x | (1<<j)] += PP[1][x];
				PQ[0][j][i] += PP[0][x];
				PQ[1][j][i] += PP[1][x];
			}
			else {
				if(f) {
					PP[0][x | (1<<j)] += PP[0][x] * P[0];
					PP[1][x | (1<<j)] += PP[1][x] * P[1];
					PQ[0][j][i] += PP[0][x] * P[0];
					PQ[1][j][i] += PP[1][x] * P[1];
					f=0;
				}
				else {
					PP[0][x | (1<<j)] += PP[0][x] * (1-P[0])/(N-1-i);
					PP[1][x | (1<<j)] += PP[1][x] * (1-P[1])/(N-1-i);
					PQ[0][j][i] += PP[0][x] * (1-P[0])/(N-1-i);
					PQ[1][j][i] += PP[1][x] * (1-P[1])/(N-1-i);
				}
			}
		}
	}
	
	FOR(i,N) FOR(x,N) FOR(y,N) if(A[x]>B[y]) ret += (A[x]+B[y]) * PQ[0][x][i]*PQ[1][y][i];
	_P("%.12lf\n",ret);
}

まとめ

1月2月の好調に反し、3月はイマイチ不調なので4月から盛り返したい。