题意:
给出n种硬币和他们的数量还有他们掷出正面朝上的概率,每一轮会投掷场上的所有硬币,只有正面朝上的硬币会留在场上,反面的硬币会被淘汰。求对于每种硬币只有他们最后能留在场上的概率。(Problem - 5985 (hdu.edu.cn))
分析:
给出的概率在0.4-0.6之间,可以想象到这个投掷次数一多对答案的影响可以忽略不计,然后给出的硬币虽然数量在1e6内,但是种类只有10以内,所以我们可以模拟对于每种硬币进行投掷,一直投掷到他们全部淘汰为止。
对于每种硬币,设他们数量为c,正面朝上的概率为p,那么他们在第n轮就全部淘汰的概率为
f[i][j]表示第i中硬币刚好在第j轮全部淘汰的概率,我们模拟1000轮。算出每种硬币没有被淘汰的概率然后其他硬币都被淘汰的概率累乘起来就是这种硬币最后能留在场上的概率。
需要注意的是,(1-f[i][j])表示这种硬币在第j轮至少还剩下一个硬币的概率,但是他不能表示仅在第j轮有剩的概率,因为他可能包含了后面轮数还有剩的概率,所以我们要想表示他仅在第j轮有剩的概率还要减去(1-f[i][j+1])
贴上代码:
#include <bits/stdc++.h>
using namespace std;
// #define int long long
#define endl '\n'
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
double f[20][1200];
int a[20];
double p[20];
double qmi(double a, int b)
{
double res = 1;
while (b)
{
if (b & 1)
res = res * a;
a = a * a;
b >>= 1;
}
return res;
}
void solve()
{
int n;
cin >> n;
memset(f, 0, sizeof(f));
memset(a, 0, sizeof(a));
memset(p, 0, sizeof(p));
for (int i = 1; i <= n; i++)
{
cin >> a[i] >> p[i];
}
for (int i = 1; i <= n; i++)
{
for (int j = 0; j <= 1000; j++)
{
double t = qmi(p[i], j);
t = 1 - t;
f[i][j] = qmi(t, a[i]);
}
}
for (int i = 1; i <= n; i++)
{
double res = 0;
for (int j = 0; j < 1000; j++)
{
double huo1 = 1 - f[i][j];
double huo2 = 1 - f[i][j + 1];
double sum = 1;
for (int k = 1; k <= n; k++)
{
if (k == i)
continue;
sum *= f[k][j];
}
sum *= (huo1 - huo2);
res += sum;
}
cout << fixed << setprecision(6) << res;
if (i != n)
cout << " ";
}
cout << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while (t--)
solve();
}