抵制克苏恩
【BZOJ4832】[Lydsy2017年4月月赛]抵制克苏恩
Description
Input
Output
对于每局游戏,输出一个数字表示总伤害的期望值,保留两位小数。
Sample Input
1 1 1 1
Sample Output
这题乍一眼看去,背景不错,虽然我没玩过炉石,好像可做的样子,然后一看数据范围,这么小,于是我立刻想到一种高级算法——打表,然鹅蒟蒻的范宏伟并不会打一个类似于暴力的东东,废话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是唯一一个可做的题,机房里也有4个A掉的。
还是自己太弱了,挺水的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\n",ans); 55 } 56 }