2016-2017-acmicpc-nordic-collegiate-programming-contest-ncpc-2016
F Fleecing the Raffle
题目链接 http://codeforces.com/gym/101550/attachments
题意:现在有n个人要抽奖,要抽p个人出来中奖,你可以随便放自己的名字到箱子中,数目不限,但是如果你的名字被抽到两次那抽奖作废,问你要放多少张你的名字在箱子中可以最大化你的中奖概率。
解题思路:
- 人数最多10^6个,直接枚举就行了。但是需要考虑怎么枚举不会炸精度。
- 假设我放x个自己的名字进去,那么中奖的概率就是C(1, x) * C(p-1, n) / C(p, n+x)。然后将公式展开,化简之后可以得到一个O(1)的递推式,递推到概率开始下降的时候停止。注意在递推的过程中要一边乘一边除,不然会炸精度。
- 深深的愧对我的高中老师,居然把化简公式推错了,还推错了好几次。
#include <bits/stdc++.h>
using namespace std;
double n, p;
int main() {
// freopen("1.in", "r", stdin);
scanf("%lf%lf", &n, &p);
double x1 = 1, x2 = p, x3 = n+1;
double ans1 = (x1*x2)/(x3/1.0), ans2;
for(double i=2.0;i<=n;i += 1.0) {
x1 = i;
x2 = p;
x3 = x3 * (n+i)/(n-p+i);
ans2 = (x1*x2)/x3;
if(ans2 < ans1)
break;
else {
ans1 = ans2;
}
}
printf("%.10f\n", ans1);
return 0;
}