题目链接
题目大意:给你n种硬币,并给你每种硬币的个数和正面朝上的概率。每次将所有的硬币投掷一下。背面朝上的抛弃。直到只剩下一种硬币或者没有硬币。最后剩下的那种硬币叫幸运硬币,问每种硬币成为幸运硬币的概率。
思路:令两个函数
f[i][k]
表示第i种硬币第K步死光的概率,所以
f[i][k]=(1−pki)ni
revf[i][k]
表示第i种硬币第k步至少有一个活着所以
revf[i][k]=1−f[i][k]
ans[i]=∑k=1100∑j=1,j!=in(rev[i][k]−rev[i][k+1])∗f[j][k−1]
此式子的意思是算第i个答案的时候,枚举步数,为了排除重复,把第i种硬币,当且至少有一个硬币活到第k步(k+1)步死的概率和其他硬币再第k步全死了的概率乘起来。
#include<bits/stdc++.h>
#define maxn 20
using namespace std;
int a[maxn];
double p[maxn];
double f[maxn][111];
double revf[maxn][111];
double ans[maxn];
double POW(double x,int n) {
double ans=1.0;
while(n) {
if(n&1) {
ans*=x;
}
x*=x;
n/=2;
}
return ans;
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--) {
memset(f,0,sizeof f);
memset(revf,0,sizeof revf);
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf("%d%lf",&a[i],&p[i]);
}
if(n==1) {
printf("1.000000\n");
continue;
}
for(int i=1;i<=n;i++) {
for(int k=1;k<=100;k++) {
double temp=POW(p[i],k);
temp=POW(1-temp,a[i]);
f[i][k]=temp;
revf[i][k]=1-temp;
}
}
/* for(int i=1;i<=n;i++) {
for(int k=1;k<=5;k++) {
cout << f[i][k] << " ";
}
cout << endl;
}
for(int i=1;i<=n;i++) {
for(int k=1;k<=5;k++) {
cout << revf[i][k] << " ";
}
cout << endl;
}*/
memset(ans,0,sizeof ans);
for(int i=1;i<=n;i++) {
for(int k=1;k<=99;k++) {
double temp=1.0;
for(int j=1;j<=n;j++) {
if(i==j) continue;
temp*=f[j][k];
// if(k<=5) {
// cout << i << " " << j << " " << k << " " ;
// cout << revf[i][k]*(f[j][k]-f[j][k-1]) << " " << endl;
//}
}
//// if(k<=5) {
// cout << i << " " << k << " " << temp << " " << revf[i][k] << endl;
// cout << revf[i][k]*temp << endl;
// }
ans[i]+=(revf[i][k]-revf[i][k+1])*temp;
}
}
for(int i=1;i<n;i++) {
printf("%.6f ",ans[i]);
}
printf("%.6f\n",ans[n]);
}
return 0;
}