Codeforces 26 D. Tickets

問題

10円のチケットをn+m枚販売する。


この国には10円と20円の二つの硬貨しかなく、
10円のみを持った客がn人、20円のみを持った客がm人来るものとする。
手元にはk枚の10円がある。


客がランダムな順番で来るとき、全ての客におつりをきちんと返せる確率はいくつか求めよ。

制約条件

n,m≦100000
k≦10

方針

nxmの格子を(0,0)の点Aから(n-1,m-1)の点Bへ行く問題に帰着される。
手元にk枚の10円があるということは、
格子の(0,k+1), (1,k+2), ……より上側の点のみを通ってゴールへ行くことに相当する。


これは、ゴールの点Bを(0,k+1),(1,k+2)……の点について折り返した点をB'とすると、
(AからBへ行く場合の数)-(AからB'へ行く場合の数)が、
有効な場合の数である。


それぞれはコンビネーションにより求まる。
コンビネーションはあらかじめ階乗を計算しておけばO(1)で求まる。
ここではn+m≦200000と大きいので、
対数を取って計算しておき、最後にe^xにする。

ソースコード

double lf[200001];
double lc(int n,int k){
	return lf[n]-lf[k]-lf[n-k];
}
void run()
{
	int n,m,k;
	cin>>n>>m>>k;
	rep(i,200000)lf[i+1]=lf[i]+log(i+1);
	if(m<=k){
		cout<<1<<endl;
		return;
	}
	if(n+k<m){
		cout<<0<<endl;
		return;
	}
	double a=lc(n+m,m-k-1)-lc(n+m,n);
	printf("%.9f\n",1-exp(a));
}