FZOJ Problem 2103 Bin & Jing in wonderland

                                                                                                              Problem 2103 Bin & Jing in wonderland

Accept: 221    Submit: 1175
Time Limit: 1000 mSec    Memory Limit : 32768 KB

 Problem Description

Bin has a dream that he and Jing are both in a wonderland full of beautiful gifts. Bin wants to choose some gifts for Jing to get in her good graces.

There are N different gifts in the wonderland, with ID from 1 to N, and all kinds of these gifts have infinite duplicates. Each time, Bin shouts loudly, “I love Jing”, and then the wonderland random drop a gift in front of Bin. The dropping probability for gift i (1≤i≤N) is P(i). Of cause, P(1)+P(2)+…+P(N)=1. Bin finds that the gifts with the higher ID are better. Bin shouts k times and selects r best gifts finally.

That is, firstly Bin gets k gifts, then sorts all these gifts according to their ID, and picks up the largest r gifts at last. Now, if given the final list of the r largest gifts, can you help Bin find out the probability of the list?

 Input

The first line of the input contains an integer T (T≤2,000), indicating number of test cases.

For each test cast, the first line contains 3 integers N, k and r (1≤N≤20, 1≤k≤52, 1≤r≤min(k,25)) as the description above. In the second line, there are N positive float numbers indicates the probability of each gift. There are at most 3 digits after the decimal point. The third line has r integers ranging from 1 to N indicates the finally list of the r best gifts’ ID.

 Output

For each case, output a float number with 6 digits after the decimal points, which indicates the probability of the final list.

 Sample Input

4 2 3 3 0.3 0.7 1 1 1 2 3 3 0.3 0.7 1 1 2 2 3 3 0.3 0.7 1 2 2 2 3 3 0.3 0.7 2 2 2

 Sample Output

0.027000 0.189000 0.441000 0.343000 
 
题意:给定N个礼物和每个礼物获得的概率P(i),编号从1到N,并且每个礼物都可以无限的获取,编号数越大代表礼物越好,Bin拿到了k个礼物,他从中挑出了r件最好的礼物送给朋友,现在只给出那最好的r个礼物,穷尽所有可能的情况,问Bin有多少的可能性最后挑出的那r个礼物就是题设给定的那r个礼物。
思路:切入点可以是题设给定的那r个礼物中编号最小的那个礼物,首先找到这个礼物z,之后考虑未确定的那k-r个礼物应该如何选取,那么未确定的那r个礼物可能是礼物z,也可能是编号比礼物z还小的礼物的组合,这里就需要分类讨论了,每次确定好礼物z在前面k-r个礼物中出现的个数I(I出现个数取值范围:0~k-r),这样再把k个礼物分成两部分来考虑,一部分是编号全小于礼物z的礼物,其余的是另一部分。
对于编号全小于礼物z的礼物,记每种礼物概率为P(a1),P(a2)...P(am),现在假设题设给定的r+I个礼物占的r+I个位置已经确定,那么剩余的k-r-I个空位都需要由编号全小于礼物z的礼物来填补,每个空位可以用这些礼物中任意一个来填补,所以全概率即为:
(P(a1)+P(a2)+...+P(am))^(k-r-I),每一个括号的含义为每个空位可以由礼物a1,a2,...,am中任意一个来填补,系数含义即为要填补(k-r-I)个空位。
再考虑题设给定的r个礼物和我们每次确定的I个礼物z,这些礼物是什么已经确定,累乘(r+I)个礼物的概率得到u,现在只是他们是在哪个位置是不固定的,我们可以随意的调换位置,这时就是一个不可放回的排列组合问题,确定这些礼物所有可能的位置后得到概率all_position,all_position*u就是后一部分礼物的概率,将前后两部分分别得到的可能性相乘就是最终的概率。
AC代码:
#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<algorithm>
#include<string>
#include<cmath>
using namespace std;
typedef long long ll;
const int N_MAX =100 ;
int N, k, r;
double P[N_MAX];
int res[N_MAX];
int num[N_MAX];
ll C[54][54];
void C_table(){
    for (int i = 1; i < 54;i++) {
        C[i][0] = C[i][i] = 1;
        for (int j = 1; j < i;j++) {
            C[i][j] = C[i-1][j] + C[i-1][j-1];
        }
    }
}

double all_position() {
    double ans = 1;
    int number = k;
    for (int i = 1; i <= N;i++) {//把所有已经知道的数放进k个位置中相应的位置所有的放法
        if (num[i]) {
            ans *= C[number][num[i]];
            number -= num[i];
        }
    }
    return ans;
}

int main() {
    int T;
    scanf("%d",&T);
    C_table();//组合排列查询表
    while (T--) {
        memset(num,0,sizeof(num));
        scanf("%d%d%d",&N,&k,&r);
        for (int i = 1; i <= N;i++) 
            scanf("%lf",&P[i]);
        double u = 1,p=0,ans=0;
        for (int i = 1; i <= r; i++) {
            scanf("%d", &res[i]);
            num[res[i]]++;//记录该礼物的数量
            u *= P[res[i]];//把已知的那些礼物的概率累乘得到的是一种情况下这些礼物的放置位置,再乘上所有可能的放置位置就得到这部分礼物概率
        }
        sort(res+1,res+r+1);
        for (int i = 1; i < res[1];i++) {//把编号比res[1]还小的礼物的概率全部累加
            p += P[i];
        }

        for (int i = r; i <=k;i++) {
            if (i > r) { 
                u *= P[res[1]];
                num[res[1]]++;
            }
            ans += u*pow(p, k - i)*all_position();

        }
        printf("%.6lf
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ZefengYao/p/6757439.html