力扣题库-掷骰子模拟详细解析

题目如下:

有一个骰子模拟器会每次投掷的时候生成一个 1 到 6 的随机数。

不过我们在使用它时有个约束,就是使得投掷骰子时,连续 掷出数字 i 的次数不能超过 rollMax[i]i 从 1 开始编号)。

现在,给你一个整数数组 rollMax 和一个整数 n,请你来计算掷 n 次骰子可得到的不同点数序列的数量。

假如两个序列中至少存在一个元素不同,就认为这两个序列是不同的。

由于答案可能很大,所以请返回 模 10^9 + 7 之后的结果。

限制如下

  • 1 <= n <= 5000
  • rollMax.length == 6
  • 1 <= rollMax[i] <= 15

解析如下:

在不考虑rollMax 限制情况下

若第1次投掷1~6,连续1次点数相同,则每个点数各有1种,即d[1][i][1] = 1(初始值),定义i为

                第一次可能投掷出的点数,X为第一次已经投掷出的点数,则第一次投掷结果表示为  X 

若第2次投掷1~6,连续2次点数相同,则每个点数各有1种,即d[2][i][2] = 1,i为第二次可能投掷

                出的点数,Y为第二次已经投掷出的点数,则两次投掷出的结果表示为 XY,且X=Y,

                则d[2][i][2] = d[1][i][1]

                投掷1~6,连续1次点数相同, 则两次投掷出的结果表示为 XY,且X != Y,在Y确定时,

                只需考虑前一次的情况,即X的值,X有6-1种选择,即d[2][i][1] = d[1][j][1] * 5 ,此处

                *5表示第一次投掷d[1][i][1] 6种情况 减去X=Y这种情况的累加,

                d[2][i][1] = d[1][a][1]+d[1][b][1]+d[1][c][1]+d[1][d][1]+d[1][e][1]

若第3次投掷1~6,连续3次点数相同, 则每个点数各有1种,即d[3][i][3] = 1,i为第三次可能投掷

                出的点数,Z为第三次已经投掷出的点数,则三次投掷出的结果表示为 XYZ,X=Y=Z,

                在Z确定时,只需要考虑前两次的投掷情况,即XY的值,因为X=Y,所以只考虑第二次

                投掷1~6,连续2次点数相同的情况即d[2][i][2]的情况,又因为Z = Y,所以Y只有一种选

                择,所以d[3][i][3] = d[2][i][2] = d[1][i][1]

                投掷1~6,连续2次点数相同, 则三次投掷出的结果表示为 XYZ,且Z = Y != X,在Z

                确定时,只需要考虑前两次的投掷情况,即XY的值,因为Y != X,所以只考虑第二次

                投掷1~6,连续1次点数相同的情况即d[2][i][1]的情况,

                又因为Z = Y,所以Y只有一种选择,所以d[3][i][2] = d[2][i][1]

                投掷1~6,连续1次点数相同,则三次投掷出的结果表示为 XYZ,且Z != Y,Y与X可相等

                可不等,

                先考虑Y != X情况,在Z确定时,只需要考虑前两次的投掷情况,即XY的值,因为Y !=                 X,所以只考虑第二次投掷1~6,连续1次点数相同的情况即d[2][i][1]的情况,

                又因为Z != Y,所以Y有6-1种选择,

                即d[3][i][1] =  d[2][i][1] * 5 = d[2][a][1]+d[2][b][1]+d[2][c][1]+d[2][d][1]+d[2][e][1]

                再考虑Y=X情况,在Z确定时,只需要考虑前两次的投掷情况,即XY的值,

                因为Y = X,所以只考虑第二次投掷1~6,连续2次点数相同的情况即d[2][i][2]的情况,

                又因为Z != Y,所以Y有6-1种选择,

                即d[3][i][1] = d[2][i][2] * 5 = d[2][a][2]+d[2][b][2]+d[2][c][2]+d[2][d][2]+d[2][e][2]注意从

                此处开始就需要考虑rollMax 的影响,暂时先忽略

                将上述两种情况相加可得:d[3][i][1] = d[2][a][1]+d[2][b][1]+d[2][c][1]+d[2][d][1]+d[2][e][1] + d[2][a][2]+d[2][b][2]+d[2][c][2]+d[2][d][2]+d[2][e][2],可以转变为下面的代码

d[3][i][1] = 0;
for(int v = 1; v <= 6; v++)
{for(int k = 1; k <= 2; k++){if(v != i){d[3][i][1] += d[2][v][k];}}
}

由上述几种投掷情况,可以发现,连续1次点数相同情况特殊,需要找上一次投掷的所用情况中排除,而超过1次点数相同情况只需要找上一次投掷中对应次数-1的结果即可,总结如下

第n次投掷1~6,连续1次点数相同的即d[n][i][1]的值为第n-1次投掷连续1次,2次到n-1次点数相同的所有情况减去每种情况下点数与i相同的情况的总和,如下

for(int v = 1; v <= 6; v++)
{for(int k = 1; k <= n - 1; k++){if(v != i){d[n][i][1] += d[n-1][v][k];}}
}
带入n = 2,结果正确

第n次投掷1~6,连续k次点数相同(k>1)的即d[n][i][k]的值第n-1次投掷连续k-1次点数相同的6种情况中第n-1次投掷与第n次投掷结果相同的一种情况,即d[n][i][k] = d[n - 1][i][k-1]

由上述总结可以得到如下的忽略rollMax 的代码

const int MOD = 1000000007;int DieSimulator2(int n)
{//状态 d[i][j][k] 表示已经完成了 i 次掷骰子,第 i 次掷的是 j,并且已经连续掷了 k 次 j 的方案数。//投掷从1开始算,所以为 n+1int[][][] d = new int[n + 1][][];for (int i = 0; i <= n; i++){d[i] = new int[6][];for (int j = 0; j < 6; j++){//此处的16表示最多连续15次,由1 <= rollMax[i] <= 15得到d[i][j] = new int[16];}}//第一次投掷出且连续掷出j的方案数只能是1,用0~5来代替投掷出1~6的点数for (int j = 0; j < 6; j++){d[1][j][1] = 1;}//第一次投掷结果已知,从第二次开始for(int i = 2; i <= n; i++){//本次投掷的结果for(int j = 0; j < 6; j++){//本次投掷的连续次数for(int k = 1; k <= n; k++){if(k != 1){//本次投掷连续次数不为1,结果为i-1次投掷中,结果为j且连续k-1次的情况d[i][j][k] += d[i - 1][j][k - 1];d[i][j][k] %= MOD;}else{//本次投掷连续次数为1,结果为i-1次投掷中,结果不为j,连续次数随意的情况总和//p为i-1次投掷的结果for (int p = 0; p < 6; p++){//lk为i-1次投掷结果的连续次数,lk不能超过ifor (int lk = 1; lk < i; lk++){//j与p不等情况的累加if(j != p){d[i][j][1] += d[i - 1][p][lk]; d[i][j][1] %= MOD;}}}}}}}int res = 0;for (int j = 0; j < 6; j++){for (int k = 1; k <= n; k++){res = (res + d[n][j][k]) % MOD;}}return res;
}

现在开始考虑rollMax的限制条件,替换其实很简单,就是在对投掷点数的连续次数的循环上加上限制即可,比如在计算本次连续投掷次数时 for(int k = 1; k <= n; k++) //本次投掷的连续次数原先的限制为连续次数不能超过总投掷次数,改为 for(int k = 1; k <= rollMax[j]; k++),不能超过rollMax对应值限制的次数即可,以及在计算本次投掷连续次数为1时,使用上一次投掷情况的地方 for (int lk = 1; lk < i; lk++) //lk为i-1次投掷结果的连续次数,原限制为连续次数不能超出i-1的投掷次数,改为for (int lk = 1; lk <= rollMax[p]; lk++),变为不能超过rollMax上次投掷值对应限制的次数即可,最后在计算总数时,一样加上限制即可。

添加限制后的代码如下

const int MOD = 1000000007;public int DieSimulator(int n, int[] rollMax)
{//状态 d[i][j][k] 表示已经完成了 i 次掷骰子,第 i 次掷的是 j,并且已经连续掷了 k 次 j 的方案数。//投掷从1开始算,所以为 n+1int[][][] d = new int[n + 1][][];for (int i = 0; i <= n; i++){d[i] = new int[6][];for (int j = 0; j < 6; j++){//此处的16表示最多连续15次,由1 <= rollMax[i] <= 15得到d[i][j] = new int[16];}}//第一次投掷出且连续掷出j的方案数只能是1,用0~5来代替投掷出1~6的点数for (int j = 0; j < 6; j++){d[1][j][1] = 1;}//第一次投掷结果已知,从第二次开始for(int i = 2; i <= n; i++){//本次投掷的结果for(int j = 0; j < 6; j++){//本次投掷的连续次数for(int k = 1; k <= rollMax[j]; k++){if(k != 1){//本次投掷连续次数不为1,结果为i-1次投掷中,结果为j且连续k-1次的情况d[i][j][k] += d[i - 1][j][k - 1];d[i][j][k] %= MOD;}else{//本次投掷连续次数为1,结果为i-1次投掷中,结果不为j,连续次数随意的情况总和//p为i-1次投掷的结果for (int p = 0; p < 6; p++){//lk为i-1次投掷结果的连续次数for (int lk = 1; lk <= rollMax[p]; lk++){//j与p不等情况的累加,且上次投掷连续次数不能超过当前投掷次数if(j != p && lk < i){d[i][j][1] += d[i - 1][p][lk];d[i][j][1] %= MOD;}}}}}}}int res = 0;for (int j = 0; j < 6; j++){for (int k = 1; k <= rollMax[j]; k++){res = (res + d[n][j][k]) % MOD;}}return res;
}

到这,解析就结束了,当然还有优化空间,但这已经石是我自己研究出来的结果了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/62235.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入浅出:PHP中的数据类型全解析

文章目录 引言理解数据类型标量类型整数 (integer)浮点数 (float)布尔值 (boolean)字符串 (string) 复合类型数组 (array)对象 (object)资源 (resource)NULL 特殊类型Callable强制类型转换 实战案例总结与展望参考资料 引言 在编程的世界里&#xff0c;数据类型是构建任何应用…

当linux可执行文件缺少或者不兼容so库时候,如何查看版本以及缺少那些库

解决方法&#xff1a; ldd 命令来验证程序是否加载了正确的库&#xff1a; 如检查linear_elasticity可执行文件缺少的库&#xff0c;用下面命令&#xff1a; ldd linear_elasticity 可以发现下面not found就是缺少的库&#xff0c;还有对应的库的位置已经版本 $ ldd lin…

第P1周:Pytorch实现mnist手写数字识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 目标 1. 实现pytorch环境配置 2. 实现mnist手写数字识别 3. 自己写几个数字识别试试具体实现 &#xff08;一&#xff09;环境 语言环境&#xff1a;Python…

Seq2Seq模型的发展历史;深层RNN结构为什么出现梯度消失/爆炸问题,Transformer为什么不会;Seq2Seq模型存在问题

目录 Seq2Seq模型的发展历史 改进不足的地方 深层RNN结构为什么出现梯度消失/爆炸问题,Transformer为什么不会 深层RNN结构为什么出现梯度消失/爆炸问题: Transformer为什么不会出现梯度消失/爆炸问题: Seq2Seq模型存在问题 T5模型介绍 Seq2Seq模型的发展历史 序列到…

网络安全技术详解:虚拟专用网络(VPN) 安全信息与事件管理(SIEM)

虚拟专用网络&#xff08;VPN&#xff09;详细介绍 虚拟专用网络&#xff08;VPN&#xff09;通过在公共网络上创建加密连接来保护数据传输的安全性和隐私性。 工作原理 VPN的工作原理涉及建立安全隧道和数据加密&#xff1a; 隧道协议&#xff1a;使用协议如PPTP、L2TP/IP…

Hive 窗口函数与分析函数深度解析:开启大数据分析的新维度

Hive 窗口函数与分析函数深度解析&#xff1a;开启大数据分析的新维度 在当今大数据蓬勃发展的时代&#xff0c;Hive 作为一款强大的数据仓库工具&#xff0c;其窗口函数和分析函数犹如一把把精巧的手术刀&#xff0c;助力数据分析师们精准地剖析海量数据&#xff0c;挖掘出深…

SCAU期末笔记 - 数据库系统概念

我校使用Database System Concepts&#xff0c;9-12章不考所以跳过&#xff0c;因为课都逃了所以复习很仓促&#xff0c;只准备过一下每一章最后的概念辨析&#xff0c;我也不知道有没有用 第1章 引言 数据库管理系统&#xff08;DBMS&#xff09; 由一个互相关联的数据的集合…

Android 12系统源码_窗口管理(九)深浅主题切换流程源码分析

前言 上一篇我们简单介绍了应用的窗口属性WindowConfiguration这个类&#xff0c;该类存储了当前窗口的显示区域、屏幕的旋转方向、窗口模式等参数&#xff0c;当设备屏幕发生旋转的时候就是通过该类将具体的旋转数据传递给应用的、而应用在加载资源文件的时候也会结合该类的A…

河南省的教育部科技查新工作站有哪些?

郑州大学图书馆&#xff08;Z12&#xff09;&#xff1a;2007年1月被批准设立“教育部综合类科技查新工作站”&#xff0c;同年12月被河南省科技厅认定为河南省省级科技查新机构。主要面向河南省的高校、科研机构、企业提供科技查新、查收查引等服务。 河南大学图书馆&#xf…

Leetcode经典题6--买卖股票的最佳时机

买卖股票的最佳时机 题目描述&#xff1a; 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。…

MCPTT 与BTC

MCPTT&#xff08;Mission Critical Push-to-Talk&#xff09;和B-TrunC&#xff08;宽带集群&#xff09;是两种关键通信标准&#xff0c;它们分别由不同的组织制定和推广。 MCPTT&#xff08;Mission Critical Push-to-Talk&#xff09;标准由3GPP&#xff08;第三代合作伙伴…

去除账号密码自动赋值时的输入框背景色

问题描述&#xff1a; 前端使用账号密码登录&#xff0c;若在网页保存过当前页面的密码和账号&#xff0c;那么当再次进入该页面&#xff0c;网页会自动的把账号和密码赋到输入框中&#xff0c;而此时输入框是带有背景色的&#xff0c;与周边的白色背景显得很不协调&#xff1…

【Pytorch】torch.reshape与torch.Tensor.reshape区别

问题引入&#xff1a; 在Pytorch文档中&#xff0c;有torch.reshape与torch.Tensor.reshape两个reshape操作&#xff0c;他们的区别是什么呢&#xff1f; 我们先来看一下官方文档的定义&#xff1a; torch.reshape&#xff1a; torch.Tensor.reshape: 解释&#xff1a; 在p…

扫码与短信验证码登录JS逆向分析与Python纯算法还原

文章目录 1. 写在前面2. 扫码接口分析2. 短信接口分析3. 加密算法还原【🏠作者主页】:吴秋霖 【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python与爬虫领域研究与开发工作!…

spring6:3容器:IoC

spring6&#xff1a;3容器&#xff1a;IoC 目录 spring6&#xff1a;3容器&#xff1a;IoC3、容器&#xff1a;IoC3.1、IoC容器3.1.1、控制反转&#xff08;IoC&#xff09;3.1.2、依赖注入3.1.3、IoC容器在Spring的实现 3.2、基于XML管理Bean3.2.1、搭建子模块spring6-ioc-xml…

【认证法规】安全隔离变压器

文章目录 定义反激电源变压器 定义 安全隔离变压器&#xff08;safety isolating transformer&#xff09;&#xff0c;通过至少相当于双重绝缘或加强绝缘的绝缘使输入绕组与输出绕组在电气上分开的变压器。这种变压器是为以安全特低电压向配电电路、电器或其它设备供电而设计…

车机端同步outlook日历

最近在开发一个车机上的日历助手&#xff0c;其中一个需求就是要实现手机端日历和车机端日历数据的同步。然而这种需求似乎没办法实现&#xff0c;毕竟手机日历是手机厂商自己带的系统应用&#xff0c;根本不能和车机端实现数据同步的。 那么只能去其他公共的平台寻求一些机会&…

OpenCV-图像阈值

简单阈值法 此方法是直截了当的。如果像素值大于阈值&#xff0c;则会被赋为一个值&#xff08;可能为白色&#xff09;&#xff0c;否则会赋为另一个值&#xff08;可能为黑色&#xff09;。使用的函数是 cv.threshold。第一个参数是源图像&#xff0c;它应该是灰度图像。第二…

力扣300.最长递增子序列

题目描述 题目链接300. 最长递增子序列 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 […

Vue CLI的作用

Vue CLI&#xff08;Command Line Interface&#xff09;是一个基于Vue.js的官方脚手架工具&#xff0c;其主要作用是帮助开发者快速搭建Vue项目的基础结构和开发环境。以下是Vue CLI的具体作用&#xff1a; 1、项目模板与快速生成 Vue CLI提供了一系列预设的项目模板&#x…