题目链接
题目大意:给你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
#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