kmjp's blog

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

M-SOLUTIONS プロコンオープン : C - Best-of-(2n-1)

Dまでは順調。
https://atcoder.jp/contests/m-solutions2019/tasks/m_solutions2019_c

問題

1回ゲームを行うと、高橋君がA%、青木君がB%で勝利し、残りC=(100-A-B)%は引き分けとなる。
どちらかが先にN回勝利するまでのゲーム回数の期待値を求めよ。

解法

先にCを処理してしまおう。
C%の確率でどちらも勝利数が増えないので、逆にどちらかの勝利回数が増えるゲーム回数の期待値は(100/(A+B))である。
よって、以後1回ゲームを行うとA:Bの確率でどちらかが勝利すると考えよう。
最後に(100/(A+B))倍すればよい。

高橋君が先にN回に到達する場合、高橋君がN回目の勝利を得る前に、高橋君が(N-1)回、青木君が0~(N-1)回勝利するケースがあるので、
 \displaystyle \sum_{i=0}^{N-1} \left( (N+i) \times {}_{N+i} C_i \times \frac{A^NB^i}{(A+B)^{N+i}} \right)
を求めればよい。
青木君がN回先に到達する場合も同様に数え上げる。

int N,A,B,C;

ll mo=1000000007;
ll comb(ll N_, ll C_) {
	const int NUM_=400001;
	static ll fact[NUM_+1],factr[NUM_+1],inv[NUM_+1];
	if (fact[0]==0) {
		inv[1]=fact[0]=factr[0]=1;
		for (int i=2;i<=NUM_;++i) inv[i] = inv[mo % i] * (mo - mo / i) % mo;
		for (int i=1;i<=NUM_;++i) fact[i]=fact[i-1]*i%mo, factr[i]=factr[i-1]*inv[i]%mo;
	}
	if(C_<0 || C_>N_) return 0;
	return factr[C_]*fact[N_]%mo*factr[N_-C_]%mo;
}
ll modpow(ll a, ll n=mo-2) {
	ll r=1;
	while(n) r=r*((n%2)?a:1)%mo,a=a*a%mo,n>>=1;
	return r;
}


void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N>>A>>B>>C;
	
	ll ret=0;
	ll Awin=A*modpow(A+B)%mo;
	ll Bwin=B*modpow(A+B)%mo;
	ll num=(A+B+C)*modpow(A+B)%mo;
	
	
	for(i=0;i<=N-1;i++) {
		ret+=comb(N-1+i,i)*modpow(Awin,N)%mo*modpow(Bwin,i)%mo*(N+i)%mo;
		ret+=comb(N-1+i,i)*modpow(Bwin,N)%mo*modpow(Awin,i)%mo*(N+i)%mo;
	}
	cout<<ret%mo*num%mo<<endl;