数位DP~

news2024/9/27 15:32:46

综述

数位DP的应用范围:

  1. 在某个区间内
  2. 有多少个
  3. 满足一定的性质

数位DP中使用的方法:

  1. 类似于前缀和。A到B相当于f[B] - a[A-1]
    这一点尤为重要,因为已经弱化了边界,使得考虑的更少
  2. 分情况讨论

image

1081. 度的数量

image

输入样例:

15 20
2
2

输出样例:

3
/*
这一道题目中的数字如果在分解之后出现某一位上的数字不是0或1,那么已订购不符合情况(K
  个互不相等)

*/

#include <bits/stdc++.h>
using namespace std;
int X, Y, K, B;
#define N 35
int f[N][N];// 组合数
void init()
{
    for(int i = 0; i < N; i++)
    {
        for(int j = 0; j <= i; j++){
            if(!j) f[i][j] = 1;
            else f[i][j] = f[i - 1][j] + f[i - 1][j - 1];
        }
    }
}
int dp(int n)
{
    if(!n) return 0;// 特判必不可少,虽然这里没什么用
    vector <int> nums;
    while(n)nums.push_back(n%B), n /= B;// 把n拆分
    int last = 0, res = 0;// res为返回值,last为走右子树已经囤积了多少个1
    for(int i = nums.size() - 1; i >= 0; i--)
    {
        int x = nums[i];
        if(x == 1)// 左右都可以
        {
            if(K - last >= 0)
                res += f[i][K - last];
            last ++;
            if(last > K) break;
        }
        else if(x > 1)// 左面就行了。要是走右面,就不满足(K个互不相等)
        {
            if(K - last >= 0) 
                res += f[i][K - last];
            if(K - last - 1 >= 0) res += f[i][K - last - 1];
            break;
        }
        if(!i && last == K) res ++;// 不要忘了这个
    }
   

    return res;
}
int main()
{
    scanf("%d%d%d%d", &X, &Y, &K, &B);
    init();
    cout << dp(Y) - dp(X - 1);
    return 0;
}

1082. 数字游戏

科协里最近很流行数字游戏。

某人命名了一种不降数,这种数字必须满足从左到右各位数字呈非下降关系,如 123,446。

现在大家决定玩一个游戏,指定一个整数闭区间 [a,b],问这个区间内有多少个不降数。

输入格式

输入包含多组测试数据。

每组数据占一行,包含两个整数 a 和 b。

输出格式

每行给出一组测试数据的答案,即 [a,b] 之间有多少不降数。

数据范围

1≤a≤b≤ 2 31 − 1 2^{31} - 1 2311

输入样例:

1 9
1 19

输出样例:

9
18

image

#include <bits/stdc++.h>
using namespace std;
#define N 15
int f[N][N];// f[i][j]状态:最高位是j,共i位的所有数字的个数
void init()
{
    for(int i = 0; i <= 9; i++) f[1][i] = 1;//只有一位数,最高位为i的方案数是1
    for(int i = 2; i < N; i++){
        for(int j = 0; j <=9; j++){
            for(int k = j; k <= 9; k++){
                f[i][j] += f[i-1][k];
            }
        }
    }
}
int dp(int n)
{
    if(!n) return 1;// 由于n == 0的时候,nums.size()为0,不会进入下面的循环,所以特判
  
    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 = last; j < x; j++) res += f[i+1][j];// 左边情况
      
        // 右边
        if(x < last) break;// 如果没有break,那么自动进入右边
        last = x;// 别忘了维护last
        if(!i) res++;// 如果安全地没有被break掉,那么就是合法的
    }
    return res;
}

int main()
{
    init();
    int A, B;
    while(cin >> A >> B)
    {
        cout << dp(B) - dp(A-1) << "\n";
    }
    return 0;
}

1083. Windy数

Windy 定义了一种 Windy 数:不含前导零且相邻两个数字之差至少为 22 的正整数被称为 Windy 数。

Windy 想知道,在 A 和 B 之间,包括 A 和 B,总共有多少个 Windy 数?

输入格式

共一行,包含两个整数 A 和 B。

输出格式

输出一个整数,表示答案。

数据范围

1≤A≤B≤ 2e9

输入样例1:

1 10

输出样例1:

9

输入样例2:

25 50

输出样例2:

20

题解

这一道题目与上一道题目有些许的差别。

数位DP中貌似默认是包含前导0的。但是这道题目并不包含,需要特判

000456在包含前导0的情况下明显不满足!

其实包含前导0也没有什么大不了的,因为当首位取0的时候,后面全部是任意取,所以可以直接枚举一下。

#include <bits/stdc++.h>
using namespace std;
#define N 13
int f[N][N];
void init()// 注意:f[i][j]中,对于j!=0的情况,就是不考虑前导0的情况。
// 事实上,j == 0 并不合法,这一种状态仅仅是为了递推而需要计算的
// 下面需要用到j == 0时,也是前面有非0数字才可以带入计算
{
    for(int i = 0; i <= 9; i++) f[1][i] = 1;// 注意:在数位DP的时候是包含前导0的
    for(int i = 2; i < N; i++){
        for(int j = 0; j <= 9; j++){
            for(int k = 0; k <= 9; k++){
                if(abs(k - j) >= 2) f[i][j] += f[i - 1][k];
            }
        }
    }
}
int dp(int n)
{
    if(!n) return 0;// 返回1或者是返回0都一样,因为作差之后就一毛一样了
    vector<int> nums;
    while(n) nums.push_back(n%10), n /= 10;

    int last = -2;// 让最高位什么都可以取
    int ans = 0;
    for(int i = nums.size() - 1; i >= 0; i--)
    {
        int x = nums[i];

        // 对于分支:
        // 左边(最高位不是0)
        for(int j = (i == nums.size() - 1); j < x; j++){
            if(abs(last - j) >= 2)ans += f[i + 1][j];// 注意判断是否合理
        }
        // 走右面
        if(abs(x - last) < 2) break;// 不合理,则退出
        last = x;// 维护last
        if(!i) ans ++;
    }
    for(int i = 1; i < nums.size(); i++){// 最高位是0的情况
        for(int j = 1; j <= 9; j ++){
            ans += f[i][j];
        }
  
    }
    return ans;
}
int main()
{
    init();
    int A, B;
    cin >> A >> B;
    cout << dp(B) - dp(A - 1);
    return 0;
}

1084. 数字游戏 II

由于科协里最近真的很流行数字游戏。

某人又命名了一种取模数,这种数字必须满足各位数字之和 m o d   n mod \space n mod n 为 0。

现在大家又要玩游戏了,指定一个整数闭区间 [a.b],问这个区间内有多少个取模数。

输入格式

输入包含多组测试数据,每组数据占一行。

每组数据包含三个整数 a,b,N

输出格式

对于每个测试数据输出一行结果,表示区间内各位数字和 m o d   n mod \space n mod n 为 0 的数的个数。

数据范围

1≤a,b≤ 2 31 − 1 2^{31} - 1 2311
1≤N<100

输入样例:

1 19 9

输出样例:

2

在 y 总的代码中,定义了三维状态,但是感觉也可以使用两维

我的f[i][j]表示有 i 位数字,并且这i位数字之和mod p 为 j 的所有数字

#include <bits/stdc++.h>
using namespace std;
int p;// 表示题目中的 N
int f[15][105];
inline int mod(int x){// 正数与%相同,负数会转化为正数
    return (x % p + p) % p;
}
void init()
{
    for(int i = 0; i < 15; i++){// 有多组测试数据
        for(int j = 0; j < p; j++)
            f[i][j] = 0;
    }
    f[0][0] = 1;// 0位数字,和为0的情况为起始情况
    for(int i = 1; i < 15; i++)
    {
        for(int j = 0; j <= 9; j++){// 最高位的取值
            for(int k = 0; k < p; k++){// 枚举第二维状态
                int o = mod(k - j);
                f[i][k] += f[i - 1][o];
            }
        }
    }
}
int dp(int n)
{
    if(!n) return 1;
    int last = 0;// 前面的和mod p
    int ans = 0;
    vector<int> nums;
    while(n) nums.push_back(n % 10), n /= 10;
    for(int i = nums.size() - 1; i >= 0; i--){
        int x = nums[i];
        for(int j = 0; j < x; j++){
            ans += f[i][mod(0 - j - last)];
        }
        last = (last + x) % p;
        if(!n && last%p == 0) ans ++;
    }
    return ans;
}
int main()
{
    int a, b;
    while(cin >> a >> b >> p){
        init();
        cout << dp(b) - dp(a - 1) << "\n";
    }
  
    return 0;
}

1085. 不要62

杭州人称那些傻乎乎粘嗒嗒的人为 62(音:laoer)。

杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。

不吉利的数字为所有含有 4 或 62 的号码。例如:62315,73418,88914 都属于不吉利号码。但是,61152 虽然含有 6 和 2,但不是 连号,所以不属于不吉利数字之列。

你的任务是,对于每次给出的一个牌照号区间 [n,m],推断出交管局今后又要实际上给多少辆新的士车上牌照了。

输入格式

输入包含多组测试数据,每组数据占一行。

每组数据包含一个整数对 nm

当输入一行为“0 0”时,表示输入结束。

输出格式

对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。

数据范围

1≤n≤m≤1e9

输入样例:

1 100
0 0

输出样例:

80

题解

这一道题目如果做拓展,就类似于设计密码

但是在这里,简单进行判断就可以了

#include <bits/stdc++.h>
using namespace std;
int f[35][10];
void init()
{
    for(int i = 0; i <= 9; i++){
        if(i == 4) continue;
        f[1][i] = 1;
    }
    for(int i = 2; i < 15; i++)
    {
        for(int j = 0; j <= 9; j++){
            if(j == 4) continue;
            for(int k = 0; k <= 9; k++){
                if(k == 4) continue;
                if(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 ans = 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 || (j == 2 && last == 6)) continue;//j == 2 && last == 6不要忘记
            ans += f[i + 1][j];
        }
      
        if(x == 4 || (x == 2 && last == 6)) break;
        last = x;// 修改last需要在判断之后
        if(!i) ans ++;
    }
    return ans;
}
int main()
{
    init();
  
    int n, m;
    while(scanf("%d%d", &n, &m), n || m){
        printf("%d\n", dp(m) - dp(n - 1));  
    }
    // cout << dp(1);
    return 0;
}

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

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

相关文章

BGP综合实验

目录 1.拓扑图 2.实验要求 3.实验思路 4.主要配置 5.测试 6.实验总结 1.拓扑图 2.实验要求 AS1存在两个环回&#xff0c;一个地址为192.168.1.0/24&#xff1b;AS3中存在两个环回&#xff0c;一个为192.168.2.0/24&#xff1b;整个AS2的IP地址为172.16.0.0/16&#xff0c…

k8s之工作机制

写在前面 本文一起看下k8s基本架构。 1&#xff1a;Kubernetes的基本架构 k8s本身也是一种分布式架构&#xff0c;也需要在多台机器&#xff08;实体机或虚拟机无差别&#xff09;部署&#xff0c;部署的机器我们叫做节点&#xff0c;其中节点分为Master node即主节点,worke…

java使用反射给对象属性赋值

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3;哈喽&#xff01;大家好&#xff0c;我是「奇点」&#xff0c;江湖人称 singularity。刚工作几年&#xff0c;想和大家一同进步&#x1f91d;&#x1f91d;一位上进心十足的【Java ToB端大厂领…

高频js手写题之实现数组扁平化、深拷贝、总线模式

前言 古人学问无遗力&#xff0c;少壮工夫老始成。纸上得来终觉浅&#xff0c;绝知此事要躬行。看懂一道算法题很快,但我们必须将这道题的思路理清、手写出来。 三道js手写题的思路和代码实现 数组扁平化 演示效果 将[1, [1, 2], [1, [2]]] 变成 [1, 1, 2, 1, 2] 第一种&…

抽象类与抽象方法

文章目录一、abstract关键字使用修饰类&#xff1a;抽象类修饰方法&#xff1a;抽象方法注意点抽象类的匿名子类一、abstract关键字使用 abstract&#xff1a;抽象的 可以修饰&#xff1a;类、方法 修饰类&#xff1a;抽象类 1、此类不可进行实例化 2、抽象类中一定有构造器…

报错 cannot import name ‘int‘ from ‘numpy‘

报错详情&#xff1a; 原因是因为np.int在numpy1.20已经被废弃掉了&#xff0c;可以通过 pip show numpy在命令行里查看。 现在使用的是np.int_ 或者 np.int32 或者 np.int64 猜测原因 但这个报错是在我自己的site-packages里的numpy的报错&#xff0c;我怀疑可能是numpy本身…

【linux】crontab

文章目录crontab简介crontab安装语法实例脚本无法执行问题常用的命令展示crontab的注意事项来源crontab简介 crontab命令常见于Unix和类Unix的操作系统之中&#xff0c;用于设置周期性被执行的指令。该命令从标准输入设备读取指令&#xff0c;并将其存放于“crontab”文件中&a…

linux系统中CAN驱动的通信方法与原理

大家好&#xff0c;今天主要和大家分享一下&#xff0c;如何使用linux系统下的CAN驱动实验。 目录 第一&#xff1a;CAN通信基本简介 第二&#xff1a;CAN通信的主要特点 第三&#xff1a;CAN通信协议 第四&#xff1a;程序代码的具体实现 第五&#xff1a;使能Linux内核自…

MATLAB-ezplot绘图函数

ezplot 函数与fplot 函数类似&#xff0c;该函数可以绘制显函数图形、隐函数图形和参数方程图形。ezplot函数的调用格式如下。 ezplot(f) ezplot(f, [ min , max ]) ezplot(f.[ xmin , xmax , ymin , ymax]) ezplot(x,y) ezplot(x,y , [tmin , tmax]) ezplot(.. . ,f…

jvm内存管理

参考链接 参考链接 Garbage Collection Concepts garbage collector的作用包括&#xff1a; 分配内存确定活着的对象不被清理回收死了的对象占用的内存 寻找和释放垃圾占用的内存空间的过程称为garbage collection一般情况下&#xff0c;整个堆或堆的一部分被填满时或者达到…

C++11 多线程

线程&#xff08;thread&#xff09;是操作系统能够进行运算调度的最小单位&#xff0c;它被包含在进程中&#xff0c;是进程中的实际运作单位&#xff0c;一条线程指的是进程中一个单一顺序的控制流&#xff0c;一个进程可以并发多个线程&#xff0c;每条线程执行不同的任务。…

FreeRTOS教程——定时器(二)

Free RTOS定时器 一、概念 一、概论 软件定时器允许设置一段时间&#xff0c;当设置的时间到达之后就执行指定的功能函数&#xff0c;被定时器 调用的这个功能函数叫做定时器的回调函数。回调函数的两次执行间隔叫做定时器的定时周期&#xff0c; 简而言之&#xff0c;当定时…

switch分支结构

一. 简介switch结合case&#xff0c;能够判断一个变量或表达式与一系列值中的某个值是否相等&#xff0c;这里的每个值都被称为一个分支。switch语句在执行时&#xff0c;会先进行值的匹配&#xff0c;匹配成功时会进入到对应case语句。再根据是否有 break语句&#xff0c;判断…

手把手教你正确地创建并配置一个SpringBoot项目

文章目录1. 安装Spring Boot Helper插件2. 创建SpringBoot项目3. 配置SpringBoot项目4. 选择修改配置&#xff08;选做&#xff09;4.1 修改端口号4.2 其他自定义配置5. SpringBoot热部署本文主要是针对IDEA社区版用户的&#xff0c;如果你是专业版的用户&#xff0c;那么是可以…

RHCE第三天之ssh远程连接服务

文章目录一、连接加密技术简介二、SSH的工作过程三、 SSH远程连接服务配置四、SSH实验SSH&#xff08;Secure Shell Protocol&#xff0c;安全的壳程序协议&#xff1a; 它可以通过数据包加密技术将等待传输的数据包加密后再传输到网络上。ssh协议本身提供两个服务器功能&#…

爬虫学习-验证码识别

反爬机制&#xff1a;验证码&#xff0c;识别验证码图片中的数据&#xff0c;用于模拟登陆识别验证码的操作人工肉眼识别(不推荐&#xff09;第三方自动识别(推荐)python第三方库&#xff1a;tesseract、ddddocr(7条消息) 小白都能轻松掌握&#xff0c;python最稳定的图片识别库…

探索用于NLP的Gensim库

Gensim的名字源自于"Generate Similar," 这个词是指Gensim可以用于生成类似的文本。这个词也可以被解释为"Generative Similarity," 表示Gensim可以用于生成相似的文本。Gensim是一个用于文本处理的库,可以用于计算文本之间的相似度,以及生成类似的文本。…

实验四:ESP8266WIFI通讯实验

本实验开发板基于&#xff1a;GD32F103我们首先需要看一下原理图 根据原理图可以看到&#xff0c;ESP8266是通过PA2 PA3这个串口进行通讯&#xff0c;PA13是控制它的复位&#xff0c;从芯片手册中可以看到PA2PA3是串口1&#xff0c;PA2是串口1的发送&#xff0c;PA3是串口1的接…

时间序列分析之ARIMA预测

预备知识 时间序列分析原理 时间序列分析之auto_arima自动调参 一、定义 ARIMA模型(Autoregressive Integrated Moving Average model)&#xff0c;差分整合移动平均自回归模型&#xff0c;又称整合移动平均自回归模型&#xff0c;时间序列预测分析方法之一。 ARIMA(p,d,q){A…

Go语言设计与实现 -- Channel

稍微需要注意一点的用法 类型断言 type dog struct {Name stringColor string }func main() {allChan : make(chan any, 10)allChan <- dog{Name: "lxy", Color: "yellow"}// 如果你这么写代码的话&#xff0c;你虽然拿到了一条狗&#xff0c;但是你…