[Lydsy2017年4月月赛]抵制克苏恩题解

  考试的时候以为就是简单的概率期望题,考完后知道是简单的概率期望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 #include<iostream>
 2 #include<cstdlib>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<queue>
 6 #include<algorithm>
 7 #include<cmath>
 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<n;o++)
23     {
24         for(int i=0;i<=7;i++)
25         {
26             for(int j=0;j<=7;j++)
27             {
28                 for(int k=0;k<=7;k++)
29                 {
30                     if(i+j+k>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<n;o++)
46     {
47         for(int i=0;i<=7;i++)
48         {
49             for(int j=0;j<=7;j++)
50             {
51                 for(int k=0;k<=7;k++)
52                 {
53                     if(i+j+k>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 }

 

posted @ 2017-07-31 07:03  Hzoi_joker  阅读(162)  评论(0编辑  收藏  举报