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}\)。因此不合法的概率就是:
因此合法的概率就是:
所以最后的代码就是个式子,很短。
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);
}