#P1634. 2023.9.24-第二题-米小游打BOSS
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 216
            Accepted: 49
            Difficulty: 5
            
          
          
          
                       所属公司 : 
                              米哈游
                                
            
                        
              时间 :2023年9月24日
                              
                      
          
 
- 
                        算法标签>动态规划          
 
2023.9.24-第二题-米小游打BOSS
题解:期望DP
这里有一个细节就是,需要使用第二种卡牌的时候,收集到的硬币才会被打出,因此需要记录打出的硬币数,然后并把怪物的血量扣除固定值x的伤害
定义f[i][j]为投掷前i次 点数总和为j的概率
最终首先判断投掷的次数num∗6是否小于h
不小于的话,就把对应的概率之和累加
f[i][j]=∑k=j−6k=j−1f[i−1][k]
C++
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1010,M=6010;
int n,t,h,x;
double f[N][M];  //投掷前i次 点数总和为j的概率
int main() {
    int cnt=0,num=0;  //硬币数量
    cin>>n>>h;
    for(int i=0;i<n;i++){
        cin>>t>>x;
        if(t==1){
            cnt+=x;
        }
        else{
            h-=x;
            num+=cnt;
            cnt=0;
        }
    }
    f[0][0]=1.0;
    for(int i=1;i<=num;i++){
        for(int j=i;j<=num*6;j++){
            for(int k=1;k<=6;k++){
                if(j>=k){
                    f[i][j]+=f[i-1][j-k]*1.0/6;
                }
            }
        }
    }
    double res=0.0;
    if(h<=num*6){
        for(int i=h;i<=num*6;i++){
            res+=f[num][i];
        }
    }
    cout<<res<<endl;
    return 0;
}
Java
import java.util.*;
public class Main {
    static final int N = 1010;
    static final int M = 6010;
    static int n, t, h, x;
    static double[][] f = new double[N][M];  // 投掷前 i 次,点数总和为 j 的概率
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int cnt = 0, num = 0;  // 硬币数量
        n = sc.nextInt();
        h = sc.nextInt();
        for (int i = 0; i < n; i++) {
            t = sc.nextInt();
            x = sc.nextInt();
            if (t == 1) {
                cnt += x;
            } else {
                h -= x;
                num += cnt;
                cnt = 0;
            }
        }
        f[0][0] = 1.0;
        for (int i = 1; i <= num; i++) {
            for (int j = i; j <= num * 6; j++) {
                for (int k = 1; k <= 6; k++) {
                    if (j >= k) {
                        f[i][j] += f[i - 1][j - k] * 1.0 / 6;
                    }
                }
            }
        }
        double res = 0.0;
        if (h <= num * 6) {
            for (int i = h; i <= num * 6; i++) {
                res += f[num][i];
            }
        }
        System.out.printf("%.4f\n", res);
    }
}
Python
N = 1010
M = 6010
f = [[0.0 for _ in range(M)] for _ in range(N)]  # 投掷前 i 次,点数总和为 j 的概率
n, h = map(int, input().split())
cnt = num = 0  # 硬币数量
for _ in range(n):
    t, x = map(int, input().split())
    if t == 1:
        cnt += x
    else:
        h -= x
        num += cnt
        cnt = 0
f[0][0] = 1.0
for i in range(1, num + 1):
    for j in range(i, num * 6 + 1):
        for k in range(1, 7):
            if j >= k:
                f[i][j] += f[i - 1][j - k] * 1.0 / 6
res = 0.0
if h <= num * 6:
    for i in range(h, num * 6 + 1):
        res += f[num][i]
print("%.4f" % res)
        题目描述
米小游正在打BOSS,当BOSS血量小于等于0时,BOSS死亡。米小游的血量为h,有一套牌,在一轮中,她会按顺序一张一张的将卡牌打出,套牌中有两种卡牌:
1.德玛西亚之力:获得x个幸运币
2.大威天龙:造成x点伤害,并投掷所有幸运币,造成等于所有幸运币掷出的点数之和的伤害
幸运币可以等概率的投掷出1~6之间的点数。米小游想知道,他的一套牌在一轮内击杀BOSS的概率
输入格式
第一行输入两个整数n(1<n<100),h(1<h<109),分别表示卡牌张数和BOSS血量。 接下来n行每行首先输入两个整数t(1≤t≤2),x(1≤x≤10),t为1表示卡牌为德玛西亚之力,t为2表示卡牌为大威天龙。
输出格式
输出一个实数表示答案,仅输出小数点后4位
样例
输入
2 5
1 1
2 1
输出
0.5000
说明
幸运币掷出4及以上的概率为0.5,再加上1点固定伤害,即可击杀BOSS。