Loading

CF26D Tickets

传送门

题目大意

卖足球赛的票,票价是 10/,你手中有 \(k\) 张 10 元钱,并且知道有 \(n\) 个人来买票时会带 10 元,\(m\) 个人会带 20 元钱。你可以顺利卖票,即每次都能找得出钱的概率是多少。

Solution

首先分析顺利卖票,由于票价是 10 元,所以带 10 元的人是不需要你找钱,相反,他们来买票还可以为你提供找 20 元的钱。所以,得出结论,10 元是好的,20 元是不好的。

我们可以先算有多少合法的序列,然后除以总方案即可。

于是,我们开始转化模型。

step 1

由上面的结论可以轻易推出,如果一种买票的顺序,使得某一次,之前带 20 元来买票的人比带 10 元的人加上原有的 \(k\) 张 10 元还要多了,那么就找不开钱,也就是没有顺利卖票了。

这很容易联想到栈,进一步的,就是典型的卡特兰数的变形。

问题就是,栈中原有 \(k\) 个元素,现在有 \(n\) 次入栈操作,\(m\) 次出栈操作,问有多少种操作顺序。

step 2

显然,这样仍不足以解决这个问题,因为毕竟不是卡特兰数的模板。我们回顾一下卡特兰数的推导:

在一个坐标系中,从原点出发,可以向上走 \(m\) 步,向右走 \(n\) 步,请问有多少种方式,可以不越过直线 \(y=x\) 并且到达点 \((n,m)\)

在这题中,可以把初始的 \(k\) 个元素转化为:在坐标轴上,从坐标 \((k,0)\) 出发。

所以题目又转化为:
在一个直角坐标系中,从点 (0,k) 出发,可以向上 m 或向右 n 步,且必须在直线 y=x 的下方(包括边界),求有多少种合法的非降路径。

step 3

最后,为了解决上面的问题,我们仍然从卡特兰数的推导中获得启发。即利用 \(P(A)=1-P(\overline{A})\)

直接算不合法的概率,当然首要还是先算不合法的方案数。

显然,可以先得出总方案数是 \(C_{n+m}^n\),其中不合法的方案,反映在坐标轴上一定是经过直线 \(y=x+1\) 的,由卡特兰数的路径计数推导,可以得出,我们只要将起点关于直线 \(y=x+1\) 对称,即将起点变成 \((-1,k+1)\),然后可以得出,不合法的方案数是 \(C_{n+m}^{k+n+1}\)。因此不合法的概率就是:

\[\frac{C_{n+m}^{k+n+1}}{C_{n+m}^n} \]

因此合法的概率就是:

\[1-\frac{C_{n+m}^{k+n+1}}{C_{n+m}^n} \]

\[=1-\frac{\frac{(n+m)!}{(m-k-1)!(k+n+1)!}}{\frac{(n+m)!}{n!m!}} \]

\[=1-\frac{n!m!}{(m-k-1)!(k+n+1)!} \]

所以最后的代码就是个式子,很短。

Code

#include<bits/stdc++.h>
#define ll long long
#define inf 1<<30
#define INF 1ll<<60
#define pb push_back
using namespace std;
int main()
{
	int n,m,k;
	scanf("%d%d%d",&n,&m,&k);
	if(n+k<m){puts("0");return 0;}//先判无解
	int up=m,down=k+n+1;
	double ans=1;
	for(int i=0;i<=k;i++,up--,down--)
		ans=ans*1.0*up/down;
	printf("%.5lf\n",1-ans);
}
posted @ 2021-04-18 15:49  ZCETHAN  阅读(43)  评论(0编辑  收藏  举报