CF107B Basketball Team
题意
yft所在的学校有 \(m\) 个社团,他所在的社团编号是 \(h\) 。现在yft受wjx命令需要从这 \(m\) 个社团中随机挑出 \(n\) 个人(\(n\) 个人包括他自己),请问挑出的人存在和yft同社团的概率是多大。
Solution
我们先考虑如果正着去选择可能的情况,\(\cdots\) ,发现是很麻烦的,所以我们要正难则反。
统计不可能的情况,最后用 \(1\) 减去即可。
设 \(sum\) 为总人数,那么从 \(sum-1\) 选 \(n-1\) 个人是总情况数,从 \(sum-a[h]\) 选 \(n-1\) 个人是不可能的情况。
则 \(ans=1-\dfrac{C_{sum-a[h]}^{n-1}}{C_{sum-1}^{n-1}}\) ,因为两个组合数的分母部分相同,可以继续化简: \(ans=1-\dfrac{(sum-a[h])*(sum-a[h]-1)\cdots (sum-a[h]-n-1)}{(sum-1)*(sum-2)\cdots (sum-n-2)}\)
代码
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=10010;
int n,m,h,a[N],sum;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
return x*f;
}
int main(){
scanf("%d%d%d",&n,&m,&h);
for(int i=1;i<=m;i++)
scanf("%d",&a[i]),sum+=a[i];
if(sum<n){
puts("-1");
return 0;
}
if(sum-a[h]<(n-1)){
puts("1");
return 0;
}
double ans=1.0;
double x=sum-a[h],y=sum-1;
for(int i=1;i<=n-1;i++){
ans*=x/y;
x--;y--;
}
printf("%.10f\n",1.0-ans);
return 0;
}