题意:
大致意思为,给定n个编号的出现概率。在这n个编号中有放回的取k次,现已知编号按大到小排后前r次的编号,求出现该种情况的概率。
题解:
做这道题我们需要知道一个求这种有放回,且存在相同物品的概率公式即 ( k ! ) / ( n u m 1 ! ∗ n u m 2 ! ∗ n u m 3 ! . . . . . . ) (k!)/(num1!*num2!*num3!......) (k!)/(num1!∗num2!∗num3!......)其中num1-n表示k次取种这n种物品出现的次数。
在这个知识前提下观察题目,发现已知序列最大的r次选取,那么剩下的编号一定小于等于r次种出现的最小值(此处记为minn)。继而我们又可以发现只有当之后的编号是minn上述公式种的num_minn是从r次中的个数加上剩余部分中minn的个数。 而编号比minn小的部分在公式中都是从1开始的,与前置已知条件无关,于是我们就可以想到将编号小于minn看作一个整体 其整体的概率就是他们概率之和,个数就是剩余部分-minn个数。这样我们只要枚举剩余部分minn出现的次数,通过第一段的公式求出概率值再求一次和便是答案
代码:
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define PB push_back
#define MP make_pair
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//逆元
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}
db a[N];
ll num[30];
int main(){
//freopen("1.txt","r",stdin);
int t;
int n,k,r;
int inp;
scanf("%d",&t);
while(t--){
db res=1.0;
memset(num,0,sizeof(num));
scanf("%d%d%d",&n,&k,&r);
for(int i=1;i<=n;i++){
scanf("%lf",&a[i]);
}
int minn=INF;
for(ll i=1;i<=r;i++){
scanf("%d",&inp);
res*=a[inp];
minn=min(inp,minn);
num[inp]++;
res*=(db)i;
res/=(db)num[inp];
}
db tmp;
db tt=0.0;
db ans=0.0;
for(int i=1;i<minn;i++){
tt+=a[i];
}
for(int i=0;i<=k-r;i++){
tmp=res;
for(int j=1;j<=i;j++){
tmp*=(db)(j+r);
tmp*=a[minn];
tmp/=(db)(num[minn]+j);
}
for(int p=i+1;p<=k-r;p++){
tmp*=(db)(p+r);
tmp*=tt;
tmp/=(db)(p-i);
}
ans+=tmp;
}
printf("%.6f\n",ans);
}
//cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
return 0;
}