计蒜客 NOIP模拟赛(3) D1T1火山喷发
火山喷发对所有附近的生物具有毁灭性的影响。在本题中,我们希望用数值来模拟这一过程。
在环境里有 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必须等于轮数
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 double cnt,f[51][51][51][51],ans; 7 int n,a[5],m; 8 int main() 9 {int l,i,j,k,p; 10 cin>>n>>m; 11 for (i=1;i<=n;i++) 12 scanf("%d",&a[i]); 13 m=min(m,a[1]+a[2]+a[3]+a[4]); 14 f[a[1]][a[2]][a[3]][a[4]]=1; 15 for (l=0;l<=m;l++) 16 { 17 for (i=0;i<=a[1];i++) 18 { 19 for (j=0;j<=a[2];j++) 20 { 21 for (k=0;k<=a[3];k++) 22 { 23 int p=a[4]-(l-(a[1]-i)-(a[2]-j)-(a[3]-k)); 24 if (a[1]-i+a[2]-j+a[4]-p+a[3]-k!=l) continue; 25 if (p<0||p>a[4]) continue; 26 if (f[i][j][k][p]==0) continue; 27 cnt=0; 28 if (i) cnt++;if (k) cnt++; 29 if (j) cnt++;if (p) cnt++; 30 if (cnt==0) continue; 31 if (i) f[i-1][j][k][p]+=f[i][j][k][p]/cnt; 32 if (j) f[i][j-1][k][p]+=f[i][j][k][p]/cnt; 33 if (k) f[i][j][k-1][p]+=f[i][j][k][p]/cnt; 34 if (p) f[i][j][k][p-1]+=f[i][j][k][p]/cnt; 35 } 36 } 37 } 38 } 39 for (i=1;i<=n;i++) 40 {ans=0; 41 if (i==1) 42 for (j=0;j<=a[2];j++) 43 for (k=0;k<=a[3];k++) 44 for (p=0;p<=a[4];p++) 45 if (a[1]+a[2]-j+a[3]-k+a[4]-p==m) 46 ans+=f[0][j][k][p]; 47 if (i==2) 48 for (j=0;j<=a[1];j++) 49 for (k=0;k<=a[3];k++) 50 for (p=0;p<=a[4];p++) 51 if (a[1]-j+a[2]+a[3]-k+a[4]-p==m) 52 ans+=f[j][0][k][p]; 53 if (i==3) 54 for (j=0;j<=a[1];j++) 55 for (k=0;k<=a[2];k++) 56 for (p=0;p<=a[4];p++) 57 if (a[1]-j+a[2]-k+a[3]+a[4]-p==m) 58 ans+=f[j][k][0][p]; 59 if (i==4) 60 for (j=0;j<=a[1];j++) 61 for (k=0;k<=a[2];k++) 62 for (p=0;p<=a[3];p++) 63 if (a[1]-j+a[2]-k+a[3]-p+a[4]==m) 64 ans+=f[j][k][p][0]; 65 printf("%.6lf\n",1-ans); 66 } 67 }