题意:有n个球,其中有0、1、2...n个黑球的概率是相等的,现在从中取出L个球,p个黑球q个白球。现在问猜一个黑球的区间,使得落在这个区间的概率大于给定的一个数值。
详见代码:
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std; int n, p, q, pri;
/*
n个球,取出p+q个球,其中黑球p个,白球q个,要求的概率最低值为p
设n个球中有k个黑球的事件为Ak ,设取出p+q个球中有p个黑球为事件B
题目所有概率为sum{p(Ak|B)}>=pri的k的取值区间
p(Ak|B)不好求解,通过贝叶斯公式p(Ak|B) = p(B|Ak)*p(Ak)/p(B)其中
p(B|Ak) = C(p, k) * C(q, n-k) / C(p+q, n);
p(B) = sum( p(B|Ak) * p(Ak) ) k = 0...n;
由于有多少个黑球是等概率的,因此p(Ak)可以提出来约掉
p(Ak|B) = p(B|Ak) / sum( p(B|Ak) );
p(Ak|B) = (C(p, k) * C(q, n-k)) / sum( (C(p, t) * C(q, n-t)) ) 其中t的取值
为枚举的区间[0, n]
上式能够用来求出某个k值的概率值,由于需要枚举一个区间,那么将
这个区间的所有概率相加即可
*/ const double eps = 1e-;
typedef long long LL;
LL tot, seq[];
LL c[][]; int sign(double x) {
return x < -eps ? - : x > eps;
} void init() { // init用来计算
c[][] = ;
for (int i = ; i <= ; ++i) {
c[][i] = ;
for (int j = ; j <= i; ++j) {
c[j][i] = c[j-][i-] + c[j][i-];
}
}
} bool check(int a, int b) {
LL x = ;
for (int i = a; i <= b; ++i) {
x += c[p][i] * c[q][n-i];
}
return sign(100.0 * x / tot - pri) >= ;
} void gao() {
tot = ;
for (int i = ; i <= n; ++i) {
tot += c[p][i] * c[q][n-i];
}
int rl, rr, len = ;
for (int i = ; i <= n; ++i) { // 枚举区间
for (int j = i; j <= n; ++j) {
if (j-i+ >= len) continue;
if (check(i, j)) {
rl = i, rr = j, len = j-i+;
}
}
}
printf("%d %d\n", rl, rr);
} int main() {
init();
while (scanf("%d %d %d %d", &n, &p, &q, &pri) != EOF) {
gao();
}
return ;
}