题面:
E. Explosion Exploit
time limit per test
2.0 s
memory limit per test
256 MB
input
standard input
output
standard output
In a two player card game, you have nn minions on the board and the opponent has mm minions. Each minion has a health between 11 and 66.
You are contemplating your next move. You want to play an "Explosion" spell which deals dd units of damage randomly distributed across all minions. The damage is dealt one unit at a time to some remaining minion on the board. Each living minion (including your own) has the same chance of receiving each unit of damage. When a minion receives a unit of damage, its health is decreased by one. As soon as the health of a minion reaches zero, it is immediately removed from the board, before the next damage is dealt. If there are no minions left on the board, any excess damage caused by the spell is ignored.
Given the current health of all minions, what is the probability that the Explosion will remove all of the opponent's minions? Note that it does not matter if all your own minions die in the process as well, and the damage continues to be dealt even if all your own minions are gone.
Input
The first line of input contains the three integers nn, mm, and dd (1≤n,m≤51≤n,m≤5, 1≤d≤1001≤d≤100). Then follows a line containing nn integers, the current health of all your minions. Finally, the third line contains mm integers, the current health of all the opponent's minions. All healths are between 11 and 66 (inclusive).
Output
Output the probability that the Explosion removes all the opponent's minions, accurate up to an absolute error of 10−610−6.
Examples
input
Copy
1 2 221 1
output
Copy
0.33333333
input
Copy
2 3 123 24 2 3
output
Copy
0.13773809
题意:
你有n个士兵,敌方有m个士兵,每一个士兵都有一定的血量(最大为6),如果血量归零,则证明该士兵死亡。现在有d点伤害,每一点伤害都会以等概率分配给任意一个人。现在问你,地方的m个士兵全都阵亡的概率。
题目分析:
首先我们可以发现,因为每个士兵的血量最大为6,且敌我双方的士兵数均为5,因此我们考虑可以用搜索的方法去解决。
因为士兵的总血量的状态比较少,因此我们可以考虑用一个12位的long long的每一位去存储每一种血量的个数。此时,这每一个12位的long long整型就唯一代表了一种状态。而又因为在搜索的过程中,每一种曾经访问过的状态所对应的概率必定是唯一的,因此我们只需要用记忆化的形式对曾经出现过的结果记进行记录,以达到剪枝的作用。
因为我们要记录的是敌军死亡的概率,因此,我们可以优先将敌军的6种血量置于12位long long的高位,这样,当我们访问到的状态值<1000000,则代表已经敌军已经已经死亡,即可直接跳出递归(又一个剪枝)。
最后只需要将相应的概率相乘并相加即为答案。
代码:
#includeusing namespace std;typedef unsigned long long ll;int mp[2][10];unordered_map dp;//充当记忆化数组ll GetSta(){//获取状态 ll res=0; for(int i=1;i<=6;i++) res*=10,res+=mp[1][i]; for(int i=1;i<=6;i++) res*=10,res+=mp[0][i]; return res;}double dfs(ll sta,int limit){ if(dp.count(sta)) return dp[sta];//如果该状态曾经访问过,则直接调用结果 if(sta<1000000) return 1;//如果该状态的值<1000000,则证明敌人已死,返回1 if(limit==0) return 0; int cnt=0; for(int i=0;i<2;i++)//获取总人数 for(int j=1;j<=6;j++) cnt+=mp[i][j]; double res=0; for(int i=0;i<2;i++){ for(int j=1;j<=6;j++){ if(!mp[i][j]) continue; mp[i][j]--; mp[i][j-1]++; ll newsta=GetSta(); double tmp=dfs(newsta,limit-1);//dfs求解下一层的答案 dp[newsta]=tmp; mp[i][j]++;//回溯 mp[i][j-1]--; res+=1.0*mp[i][j]/cnt*tmp;//统计概率 } } return res;}int main(){ int n,m,d,num; scanf("%d%d%d",&n,&m,&d); for(int i=0;i