考试的时候以为就是简单的概率期望题,考完后知道是简单的概率期望DP题,完美爆零。
这道题数据范围很小,很容易让人想到状压,不过貌似没什么可压的。那么只能说明这道题复杂度很高了,状态数组f[o][i][j][k]为第o次攻击后出现有i个1滴血的j个2滴血的,k个3滴血的情况的概率。那么转移方程就明了了。
1.f[o][i][j][k]+=f[o-1][i][j][k]/(i+j+k+1)英雄收到攻击
2.f[o][i][j][k]+=f[o-1][i+1][j][k]*(i+1)/(i+j+k+2)有一个1滴血的奴隶主被击杀。前提是i+j+k+1<=7
3.f[o][i][j][k]+=f[o-1][i-1][j+1][k-1]*(j+1)/(i+j+k)有一个2滴血的奴隶主收到攻击,召唤一个奴隶主,前提是i!=0&&k!=0
4.f[[o][i][j][k]+=f[o-1][i][j-1][k]*(k/i+j+k)有一个3滴血的奴隶主收到攻击,召唤一个奴隶主,前提是j!=0。
5由于仆从满7个后不会再召唤,所以当i+j+k=7时需要特判受到攻击却未召唤的情况,即f[o][i][j][k]+=f[o-1][i-1][j+1][k],f[o][i][j][k]+=f[o-1][i][j-1][k+1],前提分别为i!=0,j!=0。
转移方程写出来别挂精度上就行了,但是要注意我们的状态为受到攻击后场上局面的状态,真正结果为0~k-1中所有状态转移方程中1/仆从+1,一开始写的为1~k身败名裂……
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 using namespace std; 9 int t,n;10 double f[55][10][10][10];11 int main(){12 // freopen("defcthun.in","r",stdin);13 // freopen("defcthun.out","w",stdout);14 scanf("%d",&t);15 while(t--)16 {17 memset(f,0,sizeof(f));18 scanf("%d",&n);19 int xx,yy,zz;20 scanf("%d%d%d",&xx,&yy,&zz);21 f[0][xx][yy][zz]=1.0;22 for(int o=1;o 7)break;31 if(i+j+k+1<=7) f[o][i][j][k]+=f[o-1][i+1][j][k]*(double(i+1)/double(i+1+j+k+1));32 f[o][i][j][k]+=f[o-1][i][j][k]/double(i+j+k+1);33 if(i&&k) f[o][i][j][k]+=f[o-1][i-1][j+1][k-1]*(double(j+1)/double(i+k+j));34 if(j) f[o][i][j][k]+=f[o-1][i][j-1][k]*(double(k)/double(i+j+k));35 if(i+j+k==7)36 {37 if(i) f[o][i][j][k]+=f[o-1][i-1][j+1][k]*double(j+1)/double(i+j+k+1);38 if(j) f[o][i][j][k]+=f[o-1][i][j-1][k+1]*double(k+1)/double(i+j+k+1);39 }40 }41 }42 }43 }44 double sum=0.0;45 for(int o=0;o 7)break; sum+=f[o][i][j][k]*1.0/double(j+k+i+1);54 }55 }56 }57 }58 printf("%.2lf\n",sum);59 } 60 //while(1);61 return 0;62 }