[BZOJ4832]抵制克苏恩(概率期望DP)

方法一:倒推,最常规的期望DP。f[i][a][b][c]表示还要再攻击k次,目前三种随从个数分别为a,b,c的期望攻击英雄次数,直接转移即可。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #define rep(i,l,r) for (int i=l; i<=r; i++)
 6 typedef long long ll;
 7 using namespace std;
 8 
 9 const int N=60,M=10;
10 int n,a,b,c,T;
11 double f[N][M][M][M];
12 
13 int main(){
14     freopen("bzoj4832.in","r",stdin);
15     freopen("bzoj4832.out","w",stdout);
16     rep(i,1,50) rep(a,0,7) rep(b,0,7-a) rep(c,0,7-a-b){
17         int t=(a+b+c<7);
18         f[i][a][b][c]+=(f[i-1][a][b][c]+1)/(a+b+c+1);
19         if (a) f[i][a][b][c]+=f[i-1][a-1][b][c]*a/(a+b+c+1);
20         if (b) f[i][a][b][c]+=f[i-1][a+1][b-1][c+t]*b/(a+b+c+1);
21         if (c) f[i][a][b][c]+=f[i-1][a][b+1][c-1+t]*c/(a+b+c+1);
22     }
23     for (scanf("%d",&T); T--; )
24         scanf("%d%d%d%d",&n,&a,&b,&c),printf("%.2lf
",f[n][a][b][c]);
25     return 0;
26 }

方法二:用顺推做期望DP,f[x]=(f[k]+w[k][x])*p[k][x],其中k是所有能到达x的状态,w[k][x]表示这个转移的代价(攻击随从时为0,攻击英雄时为1),p[k][x]是x由k得到的概率(注意不是k转移到x的概率)。

P(x由k得到)=P(k)*P(k转移到x)/P(x),同时维护p和f即可。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #define rep(i,l,r) for (int i=l; i<=r; i++)
 6 typedef long long ll;
 7 using namespace std;
 8 
 9 const int N=60,M=10;
10 const double eps=1e-10;
11 int n,a,b,c,T;
12 double p[N][M][M][M],f[N][M][M][M];
13 
14 int main(){
15     freopen("bzoj4832.in","r",stdin);
16     freopen("bzoj4832.out","w",stdout);
17     for (scanf("%d",&T); T--; ){
18         memset(p,0,sizeof(p)); memset(f,0,sizeof(f));
19         scanf("%d%d%d%d",&n,&a,&b,&c); p[0][a][b][c]=1; double ans=0;
20         rep(i,0,n-1) rep(a,0,7) rep(b,0,7-a) rep(c,0,7-a-b){
21             int t=(a+b+c<7);
22             p[i+1][a-1][b][c]+=p[i][a][b][c]*a/(a+b+c+1);
23             p[i+1][a+1][b-1][c+t]+=p[i][a][b][c]*b/(a+b+c+1);
24             p[i+1][a][b+1][c-1+t]+=p[i][a][b][c]*c/(a+b+c+1);
25             p[i+1][a][b][c]+=p[i][a][b][c]/(a+b+c+1);
26         }
27         rep(i,0,n-1) rep(a,0,7) rep(b,0,7-a) rep(c,0,7-a-b){
28             int t=(a+b+c<7); double x=f[i][a][b][c]*p[i][a][b][c];
29             if (p[i+1][a-1][b][c]>eps)
30                 f[i+1][a-1][b][c]+=x*a/((a+b+c+1)*p[i+1][a-1][b][c]);
31             if (p[i+1][a+1][b-1][c+t]>eps)
32                 f[i+1][a+1][b-1][c+t]+=x*b/((a+b+c+1)*p[i+1][a+1][b-1][c+t]);
33             if (p[i+1][a][b+1][c-1+t]>eps)
34                 f[i+1][a][b+1][c-1+t]+=x*c/((a+b+c+1)*p[i+1][a][b+1][c-1+t]);
35             if (p[i+1][a][b][c]>eps)
36                 f[i+1][a][b][c]+=(f[i][a][b][c]+1)*p[i][a][b][c]/((a+b+c+1)*p[i+1][a][b][c]);
37         }
38         rep(a,0,7) rep(b,0,7-a) rep(c,0,7-a-b) ans+=f[n][a][b][c]*p[n][a][b][c];
39         printf("%.2lf
",ans);
40     }
41     return 0;
42 }

方法三:同样用顺推,但这里的f是上面的f*p,转移时要考虑期望的定义

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #define rep(i,l,r) for (int i=l; i<=r; i++)
 6 typedef long long ll;
 7 using namespace std;
 8 
 9 const int N=60,M=10;
10 const double eps=1e-10;
11 int n,a,b,c,T;
12 double p[N][M][M][M],f[N][M][M][M];
13 
14 int main(){
15     for (scanf("%d",&T); T--; ){
16         memset(p,0,sizeof(p)); memset(f,0,sizeof(f));
17         scanf("%d%d%d%d",&n,&a,&b,&c); p[0][a][b][c]=1; double ans=0;
18         rep(i,0,n-1) rep(a,0,7) rep(b,0,7-a) rep(c,0,7-a-b){
19             int t=(a+b+c<7);
20             p[i+1][a-1][b][c]+=p[i][a][b][c]*a/(a+b+c+1);
21             p[i+1][a+1][b-1][c+t]+=p[i][a][b][c]*b/(a+b+c+1);
22             p[i+1][a][b+1][c-1+t]+=p[i][a][b][c]*c/(a+b+c+1);
23             p[i+1][a][b][c]+=p[i][a][b][c]/(a+b+c+1);
24         }
25         rep(i,0,n-1) rep(a,0,7) rep(b,0,7-a) rep(c,0,7-a-b){
26             int t=(a+b+c<7);
27             if (p[i+1][a-1][b][c]>eps)
28                 f[i+1][a-1][b][c]+=f[i][a][b][c]*a/(a+b+c+1);
29             if (p[i+1][a+1][b-1][c+t]>eps)
30                 f[i+1][a+1][b-1][c+t]+=f[i][a][b][c]*b/(a+b+c+1);
31             if (p[i+1][a][b+1][c-1+t]>eps)
32                 f[i+1][a][b+1][c-1+t]+=f[i][a][b][c]*c/(a+b+c+1);
33             if (p[i+1][a][b][c]>eps)
34                 f[i+1][a][b][c]+=(f[i][a][b][c]+p[i][a][b][c])/(a+b+c+1);
35         }
36         rep(a,0,7) rep(b,0,7-a) rep(c,0,7-a-b) ans+=f[n][a][b][c];
37         printf("%.2lf
",ans);
38     }
39     return 0;
40 }
原文地址:https://www.cnblogs.com/HocRiser/p/9820117.html