题目连接:fzu 2103 Bin & Jing in wonderland
题目大意:给出n,k和r,表示有n种礼物,可以抽取k次礼物,要挑选r个礼物送人。然后给出n种礼物被抽中的概率,以及想要送得礼物序号。注意,抽取礼物之后只能按照礼物的标号从大到小排序后选后r个送人。例如,想要送1,1,2这样的情况,可以抽取4次。那么就只有抽取3个1和1个2的情况才可以,否则抽取两个2的话排序后即为1,1,2,2,选取后三位为1,2,2.
解题思路:将礼物的标号分为三大类,1)目标礼物中标号最小的那一个,tmp。2)比tmp标号小的礼物。3)比tmp大的礼物并且是目标礼物。
这样就可以根据组合数组计算出第三类礼物的概率P。
第二类礼物可以近似看成一种礼物,将概率想加的到pi。
然后枚举第一类礼物可能出现的次数,计算概率和ans。
答案即为ans * P。
#include <stdio.h>
#include <string.h>
#include <math.h>
typedef long long ll;
const int N = 60;
int n, k, r, tmp, v[N];
double P, p[N], pi, C[N][N];
void init() {
memset(C, 0, sizeof(C));
for (int i = 0; i <= 52; i++) {
C[0][i] = 1;
for (int j = 1; j <= i; j++)
C[j][i] = C[j - 1][i] * (i - j + 1) / j;
}
}
void input() {
P = 1; pi = 0;
scanf("%d%d%d", &n, &k, &r);
memset(v, 0, sizeof(v));
memset(p, 0, sizeof(p));
int a;
for (int i = 1; i <= n; i++) scanf("%lf", &p[i]);
for (int i = 1; i <= r; i++) {
scanf("%d", &a); v[a]++;
}
for (int i = 1; i <= n; i++) if (v[i]) {
tmp = i; break;
}
int t = k;
for (int i = tmp + 1; i <= n; i++) if (v[i]) {
P *= pow(p[i], v[i]) * C[v[i]][t];
t -= v[i];
}
for (int i = 1; i < tmp; i++) pi += p[i];
}
double solve() {
int top = k - r + v[tmp];
double ans = 0;
for (int i = v[tmp]; i <= top; i++)
ans += pow(p[tmp], i) * C[i][top] * pow(pi, top - i);
return P * ans;
}
int main () {
init();
int cas;
scanf("%d", &cas);
while (cas--) {
input();
printf("%.6lf\n", solve());
}
return 0;
}