大厂真题:【DP】米哈游2023秋招-米小游与魔法少女-奇运
题目描述与示例
题目描述
米小游都快保底了还没抽到希儿,好生气哦!只能打会活动再拿点水晶。
米小游和世界第一可爱的魔法少女 TeRiRi 正在打 BOSS,BOSS 的血量为h
,当 BOSS 血量小于等于0
时,BOSS 死亡。TeRiRi 有一套牌,在一轮中,她会按顺序一张一张的将卡牌打出,套牌中有两种卡牌:
- 时来运转:获得
x
个幸运币。 - 幸运一掷:造成
x
点伤害,并投掷所有幸运币,造成等于所有幸运币掷出的点数之和的伤害。
幸运币可以等概率的投掷出1∼6
之间的点数。 (所以为什么不叫骰子呢?)
米小游想知道,TeRiRi 的套牌在一轮内击杀 BOSS 的概率。
输入描述
第一行输入两个整数n (1≤n≤100)
,h (1≤h≤10^9)
,分别表示卡牌张数和 BOSS 血量。
接下来n
行,每行首先输入两个整数t (1≤t≤2)
,x (1≤x≤10)
,t
为1
表示卡牌为时来运转,t
为2
表示卡牌为幸运一掷。
输出描述
输出一个实数表示答案,你的答案与标准答案的误差不超过10^−4
都被认为是正确答案。
示例一
输入
2 5
1 1
2 1
输出
0.5
说明
幸运币掷出4
及以上的概率为0.5
,再加上1
点固定伤害,即可击杀BOSS。
示例二
输入
3 1145
1 4
1 9
1 9
输出
0
说明
无论如何都无法击杀BOSS。
解题思路
对于固定顺序的套牌,投掷幸运币的数量是固定的。这里要注意的是,由于时来运转之后必须接上幸运一掷才能将幸运币打出造成伤害,所以如果最后的若干张连续的卡牌是时来运转,这些最后获得的幸运币也是无法造成伤害的。
我们将造成的伤害分为两部分,固定伤害和随机伤害,前者为打出y
个幸运币必定造成的z
点伤害,后者为y
个幸运币掷出点数和的伤害。
假设整套卡牌一共投掷了y
个幸运币,造成的固定伤害为z
点,如果想要击杀BOSS,随机伤害必须至少达到h-z
点才可以。当然,如果h-z≤0
,则必定可以击杀BOSS。
问题就转换为,投掷出y
个幸运币,点数总和超过h-z
的概率是多少?
由于每一个幸运币都是独立的,在掷出第i
个幸运币时,其结果是从掷出第i-1
个幸运币时得到的各种结果转移得到的,因此我们可以使用动态规划来解决该问题。我们考虑动态规划三部曲:
dp
数组的含义是什么?
dp
数组是一个长度为(y+1)×(h-z+1)
的二维矩阵,dp[i][j]
表示掷出第i
个幸运币时,有多大的概率可以取得和为j
的结果,即造成和为j
的伤害。- 特别地,由于只需要判断伤害之和大于等于
h-z
的概率,而不用关心具体的分布,dp
数组内层的第h-z
个元素,即dp[i][h-z]
,表示求和大于等于h-z
的概率。
- 动态转移方程是什么?
- 由于幸运币掷出点数
1-6
是等概率的,故对于某一个特定的dp[i-1][j]
,在掷出第i
个幸运币时,dp[i-1][j]
的结果将等概率地转换到dp[i][j+1]
,dp[i][j+2]
,dp[i][j+3]
,dp[i][j+4]
,dp[i][j+5]
,dp[i][j+6]
,即每一个状态都可以取得1/6
的转移。 - 另外,如果
j+k
之后超过了h-z
,则将直接获得(7-k)/6 * dp[i-1][j]
的概率。
for i in range(1, y+1):for j in range(i-1, h-z+1):for k in range(1, 7):if j + k >= h - z:dp[i][h-z] += (7-k)/6 * dp[i-1][j]breakelse:dp[i][j+k] += 1/6 * dp[i-1][j]
dp
数组如何初始化?
- 考虑不投掷任何幸运币的情况,那么只有一种情况,也就是在投掷
0
个幸运币的时候获得求和为0
的概率为恒定1
。故初始化dp[0][0] = 1
dp = [[0] * (h-z+1) for _ in range(y+1)]
dp[0][0] = 1
考虑完上述问题后,代码其实呼之欲出了。
代码
Python
# 题目:【DP】米哈游2023秋招-米小游与魔法少女-奇运
# 作者:闭着眼睛学数理化
# 算法:DP
# 代码有看不懂的地方请直接在群上提问y = 0 # 掷出幸运币的总个数
z = 0 # 全部造成的固定伤害
x_temp = 0 # 时来运转获得的幸运币n, h = map(int, input().split())
for _ in range(n):t, x = map(int, input().split())# 时来运转if t == 1:x_temp += x# 幸运一掷else:y += x_tempx_temp = 0z += x# 如果固定伤害已经大于h,直接输出1
if h - z <= 0:print(1)
# 否则才需要进行dp过程
else:# 初始化dp数组# dp[i][j]表示掷出了i个幸运币时,# 有多大的概率可以取得和为j的结果,即造成和为j的伤害。dp = [[0] * (h-z+1) for _ in range(y+1)]dp[0][0] = 1# 考虑每一个幸运币for i in range(1, y+1):# 对于每一个幸运币考虑打出i-1个硬币后的# 每一种求和结果的概率# 注意,由于已经掷出了i-1个幸运币# 那么求和结果至少为i-1,因为每个幸运币点数至少为1点# 因此j遍历时起点可以从i-1开始for j in range(i-1, h-z+1):# 如果求和j尚未在上一次投掷中取得,# 则可以直接考虑下一个幸运币if dp[i-1][j] == 0:break# 遍历掷出六种不同点数k的情况,# 当前点数则可以取得j+kfor k in range(1, 7):# 如果当前点数j+k超过了击杀所需点数# 则更新dp[i][h-z]# 为dp[i-1][j]对应的概率乘以(7-k)/6if j + k >= h - z:dp[i][h-z] += (7-k)/6 * dp[i-1][j]break# 如果当前点数j+k尚未超过击杀所需点数# 则其概率由dp[i-1][j]六等分后转移得到else:dp[i][j+k] += 1/6 * dp[i-1][j]# 输出最后一行的最后一个元素# 表示打出第y个幸运币后,造成伤害大于等于h-z点的概率print(dp[y][h-z])
Java
import java.util.Scanner;public class Main {public static void main(String[] args) {int y = 0; // 掷出幸运币的总个数int z = 0; // 全部造成的固定伤害int x_temp = 0; // 时来运转获得的幸运币Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int h = scanner.nextInt();for (int i = 0; i < n; i++) {int t = scanner.nextInt();int x = scanner.nextInt();// 时来运转if (t == 1) {x_temp += x;}// 幸运一掷else {y += x_temp;x_temp = 0;z += x;}}// 如果固定伤害已经大于h,直接输出1if (h - z < 0) {System.out.println("1");}// 否则才需要进行dp过程else {// 初始化dp数组// dp[i][j]表示掷出了i个幸运币时,// 有多大的概率可以取得和为j的结果,即造成和为j的伤害。double[][] dp = new double[y + 1][h - z + 1];dp[0][0] = 1.0;// 考虑每一个幸运币for (int i = 1; i <= y; i++) {// 对于每一个幸运币考虑打出i-1个硬币后的// 每一种求和结果的概率// 注意,由于已经掷出了i-1个幸运币// 那么求和结果至少为i-1,因为每个幸运币点数至少为1点// 因此j遍历时起点可以从i-1开始for (int j = i - 1; j <= h - z; j++) {// 如果求和j尚未在上一次投掷中取得,// 则可以直接考虑下一个幸运币if (dp[i - 1][j] == 0) {break;}// 遍历掷出六种不同点数k的情况,// 当前点数则可以取得j+kfor (int k = 1; k <= 6; k++) {// 如果当前点数j+k超过了击杀所需点数// 则更新dp[i][h-z]// 为dp[i-1][j]对应的概率乘以(7-k)/6if (j + k >= h - z) {dp[i][h - z] += (7 - k) / 6.0 * dp[i - 1][j];break;}// 如果当前点数j+k尚未超过击杀所需点数// 则其概率由dp[i-1][j]六等分后转移得到else {dp[i][j + k] += 1.0 / 6.0 * dp[i - 1][j];}}}}// 输出最后一行的最后一个元素// 表示打出第n个幸运币后,造成伤害大于等于h-z点的概率System.out.println(String.format("%.5f", dp[y][h - z]));}}
}
C++
#include <iostream>
#include <vector>
#include <iomanip>using namespace std;int main() {int y = 0; // 掷出幸运币的总个数int z = 0; // 全部造成的固定伤害int x_temp = 0; // 时来运转获得的幸运币int n, h;cin >> n >> h;for (int i = 0; i < n; i++) {int t, x;cin >> t >> x;// 时来运转if (t == 1) {x_temp += x;}// 幸运一掷else {y += x_temp;x_temp = 0;z += x;}}// 如果固定伤害已经大于h,直接输出1if (h - z < 0) {cout << fixed << setprecision(10) << 1 << endl;}// 否则才需要进行dp过程else {// 初始化dp数组// dp[i][j]表示掷出了i个幸运币时,// 有多大的概率可以取得和为j的结果,即造成和为j的伤害。vector<vector<double>> dp(y + 1, vector<double>(h - z + 1, 0));dp[0][0] = 1.0;// 考虑每一个幸运币for (int i = 1; i <= y; i++) {// 对于每一个幸运币考虑打出i-1个硬币后的// 每一种求和结果的概率// 注意,由于已经掷出了i-1个幸运币// 那么求和结果至少为i-1,因为每个幸运币点数至少为1点// 因此j遍历时起点可以从i-1开始for (int j = i - 1; j <= h - z; j++) {// 如果求和j尚未在上一次投掷中取得,// 则可以直接考虑下一个幸运币if (dp[i - 1][j] == 0) {break;}// 遍历掷出六种不同点数k的情况,// 当前点数则可以取得j+kfor (int k = 1; k <= 6; k++) {// 如果当前点数j+k超过了击杀所需点数// 则更新dp[i][h-z]// 为dp[i-1][j]对应的概率乘以(7-k)/6if (j + k >= h - z) {dp[i][h - z] += (7 - k) / 6.0 * dp[i - 1][j];break;}// 如果当前点数j+k尚未超过击杀所需点数// 则其概率由dp[i-1][j]六等分后转移得到else {dp[i][j + k] += 1.0 / 6.0 * dp[i - 1][j];}}}}// 输出最后一行的最后一个元素// 表示打出第n个幸运币后,造成伤害大于等于h-z点的概率cout << fixed << setprecision(5) << dp[y][h - z] << endl;}return 0;
}
时空复杂度
时间复杂度:O(yh)
。其中y
为投掷出的幸运币的总数,h
为BOSS总血量,dp
过程需要进行双重循环。
空间复杂度:O(yh)
。dp
数组所占空间。如果使用滚动dp,空间复杂度可以降低到O(h)
华为OD算法冲刺训练
华为OD算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!
课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化
每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!
30+天陪伴式学习,20+直播课时,300+动画图解视频,200+LeetCode经典题,100+华为OD真题,还有简历修改与模拟面试将为你解锁
可查看链接 OD算法冲刺训练课程表 & OD真题汇总(持续更新)
绿色聊天软件戳 od1336了解更多
相关文章:
大厂真题:【DP】米哈游2023秋招-米小游与魔法少女-奇运
题目描述与示例 题目描述 米小游都快保底了还没抽到希儿,好生气哦!只能打会活动再拿点水晶。 米小游和世界第一可爱的魔法少女 TeRiRi 正在打 BOSS,BOSS 的血量为h,当 BOSS 血量小于等于0时,BOSS 死亡。TeRiRi 有一…...

后端面经学习自测(一)
文章目录 1、MySQL-MVCC2、MySQL-原子性怎么实现3、MySQL-持久性怎么实现隔离性怎么实现 4、操作系统-死锁产生手写死锁死锁排查 5、操作系统-避免死锁死锁的四个必要条件预防死锁 6、操作系统-pageCache是什么零拷贝 7、计算机网络-TCP的可靠性和顺序性怎么实现8、计算机网络-…...
win10、win11安装Ubuntu 22.04
目前为止(2023年10月6日),最新的 Ubuntu 版本是 Ubuntu 22.04。你可以按照以下步骤在 Windows 上使用 WSL 安装 Ubuntu 22.04: 检查系统要求: 确保你的操作系统是 Windows 10 或更高版本,并已安装 Windows …...

golang gin框架1——简单案例以及api版本控制
gin框架 gin是golang的一个后台WEB框架 简单案例 package mainimport ("github.com/gin-gonic/gin""net/http" )func main() {r : gin.Default()r.GET("/ping", func(c *gin.Context) {//以json形式输出,还可以xml protobufc.JSON…...
Redisson—分布式对象
每个Redisson对象实例都会有一个与之对应的Redis数据实例,可以通过调用getName方法来取得Redis数据实例的名称(key)。 RMap map redisson.getMap("mymap"); map.getName(); // mymap 所有与Redis key相关的操作都归纳在RKeys这…...
alsa pcm接口之在unix环境的传输方法
在unix环境,数据片段响应被接受通过standard I/O call或事件等待路径(poll或select功能),为完成列表,异步通知响应该被列举出来.ALSA实现那些方法被描述在ALSA transfers部分. 标准I/O传输(Standadrd I/O transfers) 这个标准I/O传输常常使用read和write C语言函数集,对于那些函…...

小谈设计模式(20)—组合模式
小谈设计模式(20)—组合模式 专栏介绍专栏地址专栏介绍 组合模式对象类型叶节点组合节点 核心思想应用场景123 结构图结构图分析 Java语言实现首先,我们需要定义一个抽象的组件类 Component,它包含了组合节点和叶节点的公共操作&a…...

sheng的学习笔记-【中文】【吴恩达课后测验】Course 1 - 神经网络和深度学习 - 第三周测验
课程1_第3周_测验题 目录:目录 第一题 1.以下哪一项是正确的? A. 【 】 a [ 2 ] ( 12 ) a^{[2](12)} a[2](12)是第12层,第2个训练数据的激活向量。 B. 【 】X是一个矩阵,其中每个列都是一个训练示例。 C. 【 】 a 4 […...

一文详解动态链表和静态链表的区别
1、引言 本文主要是对动态链表和静态链表的区别进行原理上的讲解分析,先通过对顺序表和动态链表概念和特点的原理性介绍,进而引申出静态链表的作用,以及其概念。通过这些原理性的概述,最后总结归纳出动态链表和静态链表的区别。本…...

[C国演义] 第十三章
第十三章 三数之和四数之和 三数之和 力扣链接 根据题目要求: 返回的数对应的下标各不相同三个数之和等于0不可包含重复的三元组 – – 即顺序是不做要求的 如: [-1 0 1] 和 [0, 1, -1] 是同一个三元组输出答案顺序不做要求 暴力解法: 排序 3个for循环 去重 — — N^3, …...

<二>Qt斗地主游戏开发:过场动画的实现
1. 过场动画效果 2. 思路分析 过场动画较为简单,只有一个进度条在进行滚动,因此实现起来不需要动画相关处理,仅需要图片和定时器设定,让进度条动起来即可。我们可以创建一个对话框,设定背景图片以及对话框透明无边框&a…...
链式法则(Chain Rule)
定义 链式法则(Chain Rule)是概率论和统计学中的一个基本原理,用于计算联合概率分布或条件概率分布的乘积。它可以用于分解一个复杂的概率分布为多个较简单的条件概率分布的乘积,从而简化概率分析问题。 链式法则有两种常见的形…...

AUTOSAR COM模块框架梳理
框架: COM的功能主要就是两个: 把IPDU内的signal提取出来提供给SWC使用,把SWC发送的signal拷贝到IPDU buffer内 所以,COM的关键字是 signal, signal group, IPDU, IPDU group Signal group 是为了保证 Complex Data Types 的数…...
详细介绍区块链之挖矿
对不起,大家,这篇文章对作者来说实在是太有意义和含金量了,作者想把它设置为关注博主才能见全文,请大家理解!如果觉得还是看不懂,抱歉耽误大家的时间,就请取消关注!!&…...
华为OD机试真题-路灯照明问题(Java/C++/Go/Python)
【华为OD机试真题】路灯照明问题(Java/C++/Go/Python) 题目描述 在一条笔直的公路上安装了N个路灯,从位置0开始安装,路灯之间间距固定为100米。 每个路灯都有自己的照明半径,请计算第一个路灯和最后一个路灯之间,无法照明的区间的长度和。 输入描述 第一行为一个数N…...
嵌入式技术面试基本规则
潜规则1:面试的本质不是考试,而是告诉面试官你会做什么 经验不够的小伙伴特别容易犯的一个错误,不清楚面试官到底想问什么,其实整个面试中面试官并没有想难倒你的意思,只是想通过提问的方式来知道你会什么。 比如stm…...

osg实现自定义插件读取自定义格式的模型文件到场景
目录 1. 前言 2. 预备知识 3. 工具、原料 4. 代码实现 1. 前言 osg提供了很多插件来读取模型文件到场景中,这些插件支持大约70种格式类型的文件,但现实中的文件是各式各样,osg不可能囊括所有类型文件,当osg不支持某种类型格式…...

redis进阶
redis.conf 启动的时候就通过配置文件来启动的! # 这个不是配置的,就是在这儿说明一下 # 当配置中需要配置内存大小时,可以使用 1k, 5GB, 4M 等类似的格式,其转换方式如下(不区分大小写) # # 1k > 1000 bytes # 1kb > 102…...

(一)正点原子STM32MP135移植——准备
一、简述 使用板卡:正点原子的ATK-DLMP135 V1.2 从i.mx6ull学习完过来,想继续学习一下移植uboot和内核的,但是原子官方没有MP135的移植教程,STM32MP157的移植教程用的又是老版本的代码,ST官方更新后的代码不兼容老版本…...
Kotlin的关键字 lateinit 和 lazy
序、完善一下曾经的草稿。 Kotlin通常要求我们在定义属性后立即对起进行初始化,当我们不知道理想的初始值时,这样做似乎很奇怪,尤其是在生命周期驱动android属性的情况下。 lateinit 简介 lateinit,Kotlin提供的一个可以延迟初…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...

GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

《信号与系统》第 6 章 信号与系统的时域和频域特性
目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...

Qt的学习(一)
1.什么是Qt Qt特指用来进行桌面应用开发(电脑上写的程序)涉及到的一套技术Qt无法开发网页前端,也不能开发移动应用。 客户端开发的重要任务:编写和用户交互的界面。一般来说和用户交互的界面,有两种典型风格&…...
多元隐函数 偏导公式
我们来推导隐函数 z z ( x , y ) z z(x, y) zz(x,y) 的偏导公式,给定一个隐函数关系: F ( x , y , z ( x , y ) ) 0 F(x, y, z(x, y)) 0 F(x,y,z(x,y))0 🧠 目标: 求 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z、 …...