AcWIng1085. 不要62(数位DP)

news/2024/10/20 11:29:36/

文章目录

  • 一、问题
  • 二、分析
  • 三、代码

一、问题

在这里插入图片描述

二、分析

这道题涉及的算法是数位DP。如果大家不懂数位DP的话,可以先去看作者之前的文章:第五十章 动态规划——数位DP模型

假设一个数 n n n,我们先求出从 1 1 1 n n n当中,所有不含数字4和62的数字的个数。我们将这个过程封装为一个函数,先来分析一下这个函数怎么写。

按照数位DP的分析逻辑,先将 n n n的每一位存储在 v e c t o r vector vector中,然后从高位开始枚举。

对于其中的任意一位 a a a。由于我们求的是从 1 1 1 n n n的数字,所以在该位之前所有高位都相同的条件下,该位所填的数字必须是 ≤ a \leq a a的,这样做才能小于等于 n n n

我们现在分成两类,一类是该位 < a <a <a
在这种情况下,我们就无需考虑数字大小的问题了,因为该位小于 a a a,所以比该位小的位可以随便写,无论怎么写都是小于 a a a的。那么我们又怎么统计该情况下,符合题目要求的数字个数呢?

求个数的过程就是我们真正需要写DP的部分。这里我们先直接利用DP的状态定义解决这个函数,具体的状态转移我们后面再说。
我们让状态: f [ i ] [ k ] f[i][k] f[i][k]表示数字有 i i i位,并且第 i i i位是 k k k的情况下, 数字中不含 4 4 4 62 62 62的数字个数。那么我们这里直接将 k k k 0 0 0 a − 1 a-1 a1进行枚举 f [ i ] [ k ] f[i][k] f[i][k],然后将这些累加到结果上。但并不是所有都能累加的,比如 k = 4 k=4 k=4的时候,就不可以。再比如上一位的数字和当前位的 k k k组成 62 62 62的时候,也是不能算的。(这就说明我们还需要一个 l a s t last last变量去存储上一位的数字。)

当这一位是 a a a的时候,我们只需要接着往后讨论,但是如果第 a a a位是 4 4 4的话,说明无论后面是什么,组成的数字都是不符合题目要求的,直接挑出循环即可。

接下来,我们分析一下状态转移应该怎么写?

f [ i ] [ k ] + = f [ i − 1 ] [ j ] f[i][k]+=f[i-1][j] f[i][k]+=f[i1][j]
上面的 j j j是从 0 0 0 9 9 9的。但是要注意的是, j j j k k k不能是 4 4 4,并且 j j j k k k不能组成 62 62 62

三、代码

#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>using namespace std;const int N = 35;int f[N][10];void init()
{for (int i = 0; i <= 9; i ++ )if (i != 4)f[1][i] = 1;for (int i = 1; i < N; i ++ )for (int j = 0; j <= 9; j ++ ){if (j == 4) continue;for (int k = 0; k <= 9; k ++ ){if (k == 4 || j == 6 && k == 2) continue;f[i][j] += f[i - 1][k];}}
}
int dp(int n)
{if (!n) return 1;vector<int> nums;while (n) nums.push_back(n % 10), n /= 10;int res = 0;int last = 0;for (int i = nums.size() - 1; i >= 0; i -- ){int x = nums[i];for (int j = 0; j < x; j ++ ){if (j == 4 || last == 6 && j == 2) continue;res += f[i + 1][j];}if (x == 4 || last == 6 && x == 2) break;last = x;if (!i) res ++ ;}return res;
}
int main()
{init();int l, r;while (cin >> l >> r, l || r){cout << dp(r) - dp(l - 1) << endl;}return 0;
}

http://www.ppmy.cn/news/61384.html

相关文章

xawtv涉及的vivid系统调用分析

xawtv涉及的vivid系统调用分析 文章目录 xawtv涉及的vivid系统调用分析调用过程分析摄像头驱动程序必需的11个ioctl非必须必须 分析数据的获取过程1.请求分配缓冲区: ioctl(4, VIDIOC_REQBUFS // 请求系统分配缓冲区2.查询映射缓冲区:3.把缓冲区放入队列:4.启动摄像头5.用selec…

代码随想录算法训练营第三十天 | 航班问题、二维回溯

回溯法小结 本周小结&#xff01;&#xff08;回溯算法系列三&#xff09; | 代码随想录 (programmercarl.com) 性能分析 子集问题分析&#xff1a; 时间复杂度&#xff1a;O(n 2n)&#xff0c;因为每一个元素的状态无外乎取与不取&#xff0c;所以时间复杂度为O(2n)&…

登山 最长上升子序列问题 线性DP

&#x1f351; 算法题解专栏 &#x1f351; 洛谷 登山 登山 题目描述 五一到了&#xff0c;ACM队组织大家去登山观光&#xff0c;队员们发现山上一个有N个景点&#xff0c;并且决定按照顺序来浏览这些景点&#xff0c;即每次所浏览景点的编号都要大于前一个浏览景点的编号。…

用户界面对象的线程亲缘性第二篇: 设备上下文

在上一篇文章中&#xff0c;我们简单地介绍了控制窗口句柄的线程亲缘性规则。 今天&#xff0c;我们来讲讲设备上下文(Device Context, 简称 DC) 。 设备上下文也有一定程度的线程亲缘性。调用 DC 相关函数&#xff0c;例如 GetDC 的线程&#xff0c;必须在同一个线程中调用其…

PID整定二:基于Ziegler-Nichols的频域响应

PID整定二&#xff1a;基于Ziegler-Nichols的频域响应 1参考2连续Ziegler-Nichols方法的PID整定2.1整定方法2.2仿真示例 1参考 1.1根轨迹图的绘制及分析 1.2计算机控制技术01-3.4离散系统的根轨迹分析法 1.3PID控制算法学习笔记 2连续Ziegler-Nichols方法的PID整定 2.1整定…

leetcode:234.回文链表(详解)

前言&#xff1a;内容包括-题目&#xff0c;代码实现&#xff0c;大致思路&#xff0c;代码解读 题目&#xff1a; 给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为回文链表。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&…

Java日志详解

文章目录 1.日志的概述1.1 日志文件1.1.1 调试日志1.1.2 系统日志 1.2 JAVA日志框架1.2.1 为什么要用日志框架1.2.2 日志框架和日志门面 2.JUL2.1 JUL简介2.2 JUL组件介绍2.3 JUL的基本使用2.3.1 日志输出的级别2.3.2 日志的输出方式2.3.3 自定义日志的级别2.3.4 将日志输出到具…

【产品方案】后台管理系统设计思路

第一章 前言 相比前端设计&#xff0c;我更喜欢设计后台管理系统。如果说前端设计考验的是共情能力&#xff0c;那后台管理系统设计考研的就是逻辑能力&#xff0c;前者需要站在用户的角度&#xff0c;后者是站在管理者的角度思考。 有幸参与了公司不少业务系统从“0-1”的设计…