抵制克苏恩

 

【BZOJ4832】[Lydsy2017年4月月赛]抵制克苏恩

 

Description

 

小Q同学现在沉迷炉石传说不能自拔。他发现一张名为克苏恩的牌很不公平。如果你不玩炉石传说,不必担心,小Q同学会告诉你所有相关的细节。炉石传说是这样的一个游戏,每个玩家拥有一个 30 点血量的英雄,并且可以用牌召唤至多 7 个随从帮助玩家攻击对手,其中每个随从也拥有自己的血量和攻击力。小Q同学有很多次游戏失败都是因为对手使用了克苏恩这张牌,所以他想找到一些方法来抵御克苏恩。他去求助职业炉石传说玩家椎名真白,真白告诉他使用奴隶主这张牌就可以啦。如果你不明白我上面在说什么,不必担心,小Q同学会告诉你他想让你做什么。现在小Q同学会给出克苏恩的攻击力是 K ,表示克苏恩会攻击 K 次,每次会从对方场上的英雄和随从中随机选择一个并对其产生 1 点伤害。现在对方有一名克苏恩,你有一些奴隶主作为随从,每名奴隶主的血量是给定的。
如果克苏恩攻击了你的一名奴隶主,那么这名奴隶主的血量会减少 1 点,当其血量小于等于 0 时会死亡,如果受到攻击后不死亡,并且你的随从数量没有达到 7 ,这名奴隶主会召唤一个拥有 3 点血量的新奴隶主作为你的随从;如果克苏恩攻击了你的英雄,你的英雄会记录受到 1 点伤害。你应该注意到了,每当克苏恩进行一次攻击,你场上的随从可能发生很大的变化。小Q同学为你假设了克苏恩的攻击力,你场上分别有 1 点、 2 点、 3 点血量的奴隶主数量,你可以计算出你的英雄受到的总伤害的期望值是多少吗?

 

Input

 

输入包含多局游戏。
第一行包含一个整数 T (T<100) ,表示游戏的局数。
每局游戏仅占一行,包含四个非负整数 K, A, B 和 C ,表示克苏恩的攻击力是 K ,你有 A 个 1 点血量的奴隶主, B 个 2 点血量的奴隶主, C 个 3 点血量的奴隶主。
保证 K 是小于 50 的正数, A+B+C 不超过 7 。

 

Output

 

对于每局游戏,输出一个数字表示总伤害的期望值,保留两位小数。

 

Sample Input

 

1
1 1 1 1

 

Sample Output

 

0.25

 

这题乍一眼看去,背景不错,虽然我没玩过炉石,好像可做的样子,然后一看数据范围,这么小,于是我立刻想到一种高级算法——打表,然鹅蒟蒻的范宏伟并不会打一个类似于暴力的东东,废话tm会打就A了啊,仔细分析一下题目的话,很容易想到这是一个dp,但是考试的时候一直在想状态怎么设计,因为考试的时候脑抽这题看上去状态不太好设计的样子其实很好设计,每次克苏恩攻击一次时都有可能对场上的局面发生很大的变化,但是如果好好分析一下的话其实克苏恩每次攻击无非有那么几种结果:(其实这题的关键就是每次攻击奴隶主的个数变化)

①克苏恩攻击英雄那么不用考虑奴隶主的变化,因为奴隶主没有变化,而英雄血量无穷大,(貌似这个点阻止了wmz神犇和lnc神犇A题,嘤嘤嘤)

②克苏恩攻击一血奴隶主,只需一血奴隶主个数减减,乘以这种情况发生的概率,转移完毕

③克苏恩攻击二血奴隶主,若场上奴隶总数未满7个,则三血奴隶主++,二血奴隶主减减,一些奴隶主++,乘以这种情况发生的概率,转移完毕

  若场上奴隶主满7个,则二血奴隶主减减,一些奴隶主++,乘以这种情况发生的概率,转移完毕

④克苏恩攻击三血奴隶主,若场上奴隶总数未满7个,三血奴隶主不变,二血奴隶主++

乘以这种情况发生的概率,转移完毕

  若场上奴隶总数满7个,三血奴隶主减减,二血奴隶主++,乘以这种情况发生的概率,转移完毕

然后dp式就显而易见了

 因为克苏恩对英雄的伤害与每种仆从的数量有关,所以我们设f[i][j][k][l]表示第i次攻击时,仆从一滴血的有j个,两滴血的有k个,三滴血的有l个。

   那么假设已知f[i][j][k][l]的值,考虑其可以转移到的状态。

   1.此次攻击英雄  f[i+1][j][k][l]

   2.攻击一个血量为1的仆从  f[i+1][j-1][k][l]

   3.攻击一个血量为2的仆从  f[i+1][j+1][k-1][l]OR f[i+1][j+1][k-1][l+1]

   4.攻击一个血量为3的仆从  f[i+1][j][k+1][l-1]OR f[i+1][j][k+1][l]

   那么最后答案应为Σf[i][j][k][l]*1.0*1/(j+k+l+1)。

完毕。

PS:考试时觉得这题十分不可做,看了20分钟之后,就开始打T2暴力,实际上T1是唯一一个可做的题,机房里也有4A掉的。

还是自己太弱了,挺水的dp都觉得不可做,以后再做dp题,我一定自己好好推式子,自己码代码,加油吧。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<vector>
 7 #include<queue>
 8 double p[35][8][8][8],f[35][8][8][8];
 9 using namespace std;
10 int main(){
11     int T;
12     scanf("%d",&T);
13     while(T--){
14         memset(f,0,sizeof(f));
15         int k;
16         scanf("%d",&k);
17         int a,b,c;
18         scanf("%d%d%d",&a,&b,&c);
19         f[1][a][b][c]=1.0;
20         double ans=0;
21         for(int i=1;i<=k;i++){
22             for(int j=0;j<=7;j++){
23                 for(int k=0;k<=7;k++){
24                     for(int l=0;l<=7;l++){
25                         if(j+k+l>7) break;
26                         double poss=1.0/(j+k+l+1);
27                         f[i+1][j][k][l]+=poss*f[i][j][k][l];//英雄被打
28                         f[i+1][j-1][k][l]+=poss*j*f[i][j][k][l];//一血被打
29                         if(j+k+l!=7){//可加奴隶
30                             f[i+1][j+1][k-1][l+1]+=poss*k*f[i][j][k][l];//二血被打
31                             f[i+1][j][k+1][l]+=poss*l*f[i][j][k][l];//三血被打
32                         } 
33                         else /*if(j+k+l==7)*/{//不可加奴隶
34                             f[i+1][j+1][k-1][l]+=poss*k*f[i][j][k][l];//二血被打且不加奴隶 
35                             f[i+1][j][k+1][l-1]+=poss*l*f[i][j][k][l];//三血被打且不加奴隶 
36                         }
37                         ans+=f[i][j][k][l]*poss;
38                     }
39                 }
40             }
41         }
42         /*for(int i=1;i<=k;i++){
43             for(int j=0;j<=7;j++){
44                 for(int k=0;k+j<=7;k++){
45                     for(int l=0;l+k+j<=7;l++){
46                         cout<<f[i][j][k][l]<<" ";
47                     }
48                     cout<<endl;
49                 }
50                 cout<<endl;
51             }
52             cout<<endl;
53         }*/
54         printf("%.2lf
",ans);
55     }
56 }
View Code
原文地址:https://www.cnblogs.com/leom10/p/11166472.html