Gym 101933E(状态压缩+记忆化搜索)

传送门

题面:

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 2
2
1 1

output

Copy

0.33333333

input

Copy

2 3 12
3 2
4 2 3

output

Copy

0.13773809

题意:

    你有n个士兵,敌方有m个士兵,每一个士兵都有一定的血量(最大为6),如果血量归零,则证明该士兵死亡。现在有d点伤害,每一点伤害都会以等概率分配给任意一个人。现在问你,地方的m个士兵全都阵亡的概率。

题目分析:

    首先我们可以发现,因为每个士兵的血量最大为6,且敌我双方的士兵数均为5,因此我们考虑可以用搜索的方法去解决。

    因为士兵的总血量的状态比较少,因此我们可以考虑用一个12位的long long的每一位去存储每一种血量的个数。此时,这每一个12位的long long整型就唯一代表了一种状态。而又因为在搜索的过程中,每一种曾经访问过的状态所对应的概率必定是唯一的,因此我们只需要用记忆化的形式对曾经出现过的结果记进行记录,以达到剪枝的作用。

    因为我们要记录的是敌军死亡的概率,因此,我们可以优先将敌军的6种血量置于12位long long的高位,这样,当我们访问到的状态值<1000000,则代表已经敌军已经已经死亡,即可直接跳出递归(又一个剪枝)。

    最后只需要将相应的概率相乘并相加即为答案。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
int mp[2][10];
unordered_map<ll,double>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<n;i++){
        scanf("%d",&num);
        mp[0][num]++;
    }
    for(int i=0;i<m;i++){
        scanf("%d",&num);
        mp[1][num]++;
    }
    double res=dfs(GetSta(),d);
    printf("%.8f\n",res);
}

 

转载于:https://www.cnblogs.com/Chen-Jr/p/11007169.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值