kmjp's blog

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

yukicoder : No.173 カードゲーム(Medium)

最初Hardの問題と勘違い→Mediumが解けず時間浪費→ラスト5分で誤差に気づく→終了後Hardがあっさり通った。
前回のVK Cupといいひどすぎる。
http://yukicoder.me/problems/325

問題

A君B君の2人は1~1000の異なる整数値が書かれたN枚のカードA[i],B[i]を持っている。

2人は手持ちのカードを1枚出す、というゲームをN回繰り返す。
大きな数値の書かれた方が勝ちとなり、2枚の数値の合計分の得点を得る。
なお、2人のカードの出し方は以下の通りである。

  • 手持ちのカードが1枚の時はそれを出す。
  • 手持ちのカードが2枚以上の時:
    • A君は確率Pa、B君はPbで手持ちの最小値のカードを出す。
    • A君は確率(1-Pa)、B君は(1-Pb)で手持ちのうち最小値以外のカードのいずれかを等確率で出す。

最終的にA君が取得得点で勝つ確率を求めよ。

解法

誤差が0.5%まで許容されるので、シミュレーションを繰り返せばばよい。

シミュレーションではなく、精度高くやろうとするとHardより難しいかも。

int N,T;
double P[2];
int A[30],B[30];
int win,tot;

vector<int> getrandvec(double p) {
	int i,x;
	vector<int> v,r;
	FOR(i,N) v.push_back(i);
	FOR(i,N-1) {
		double d = rand()*1.0/RAND_MAX;
		if(d<p) x=0;
		else x=1+(N-1-i)*(d-p)/(1-p);
		
		r.push_back(v[x]);
		v.erase(v.begin()+x);
	}
	r.push_back(v[0]);
	return r;
}

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N>>P[0]>>P[1];
	FOR(i,N) cin>>A[i], T+=A[i];
	FOR(i,N) cin>>B[i], T+=B[i];
	sort(A,A+N);
	sort(B,B+N);
	
	srand(time(NULL));
	
	FOR(i,200000) {
		tot++;
		vector<int> VA,VB;
		VA=getrandvec(P[0]);
		VB=getrandvec(P[1]);
		x=0;
		FOR(y,N) if(A[VA[y]]>B[VB[y]]) x+=A[VA[y]]+B[VB[y]];
		if(x>T/2) win++;
	}
	
	_P("%.12lf\n",1.0*win/tot);
}

まとめ

解けなくても先に後ろの問題読むべきだなぁ。