火山喷发对所有附近的生物具有毁灭性的影响。在本题中,我们希望用数值来模拟这一过程。
在环境里有 nnn 个生物分别具有 A1,A2,⋯,An点生命值,一次火山喷发总计 M轮,每轮造成 1点伤害,等概率地分给所有存活的生物,即如果目前有 K 个活着的生物,每个生物受到这点伤害的概率是 1/K。如果一个生物的生命值减为 0,它会立即死去,此后都不会再占用受到伤害的概率。如果没有生物存活,那么将没有生物会受到伤害。
现在你的任务是,给定 n,M 和全部生物的生命值,问每个生物火山喷发后依然存活的概率。
输入格式
第一行两个正整数 n 和 M。
第二行 n 个正整数 A1,...,An。
输出格式
n行,第 i 行一个数表示第 i 个生物存活下来的概率,保留小数点后六位。
数据范围与约定
对于 10% 的数据 N=1。
对于 30% 的数据 N=2。
对于全部数据 N≤4,M≤120,Ai≤50。
样例输入1
1 2
1
样例输出1
0.000000
样例输入2
3 15
2 12 2
样例输出2
0.001684
0.996632
0.001684
f[i][j][k][p]表示生命值为i,j,k,p时的概率
那么我们枚举轮数和4个生物的HP,就可以转移
但是O(120*50^4)显然超时
但我们知道轮数和3个生物的HP,显然可以推出第四个
所以O(120*50^3)就够了
还有要注意枚举的HP对应的损失HP必须等于轮数
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
double cnt,f[][][][],ans;
int n,a[],m;
int main()
{int l,i,j,k,p;
cin>>n>>m;
for (i=;i<=n;i++)
scanf("%d",&a[i]);
m=min(m,a[]+a[]+a[]+a[]);
f[a[]][a[]][a[]][a[]]=;
for (l=;l<=m;l++)
{
for (i=;i<=a[];i++)
{
for (j=;j<=a[];j++)
{
for (k=;k<=a[];k++)
{
int p=a[]-(l-(a[]-i)-(a[]-j)-(a[]-k));
if (a[]-i+a[]-j+a[]-p+a[]-k!=l) continue;
if (p<||p>a[]) continue;
if (f[i][j][k][p]==) continue;
cnt=;
if (i) cnt++;if (k) cnt++;
if (j) cnt++;if (p) cnt++;
if (cnt==) continue;
if (i) f[i-][j][k][p]+=f[i][j][k][p]/cnt;
if (j) f[i][j-][k][p]+=f[i][j][k][p]/cnt;
if (k) f[i][j][k-][p]+=f[i][j][k][p]/cnt;
if (p) f[i][j][k][p-]+=f[i][j][k][p]/cnt;
}
}
}
}
for (i=;i<=n;i++)
{ans=;
if (i==)
for (j=;j<=a[];j++)
for (k=;k<=a[];k++)
for (p=;p<=a[];p++)
if (a[]+a[]-j+a[]-k+a[]-p==m)
ans+=f[][j][k][p];
if (i==)
for (j=;j<=a[];j++)
for (k=;k<=a[];k++)
for (p=;p<=a[];p++)
if (a[]-j+a[]+a[]-k+a[]-p==m)
ans+=f[j][][k][p];
if (i==)
for (j=;j<=a[];j++)
for (k=;k<=a[];k++)
for (p=;p<=a[];p++)
if (a[]-j+a[]-k+a[]+a[]-p==m)
ans+=f[j][k][][p];
if (i==)
for (j=;j<=a[];j++)
for (k=;k<=a[];k++)
for (p=;p<=a[];p++)
if (a[]-j+a[]-k+a[]-p+a[]==m)
ans+=f[j][k][p][];
printf("%.6lf\n",-ans);
}
}