-数位DP

article/2025/9/13 12:57:11

目录

1、 数位和 

2、不要62

3、数数1

4、数数2

5、数数3


1、 数位和 

// 数位和#include<bits/stdc++.h>
using namespace std;
int c[21];
long long l, r, ans[10], f[17];inline void calc(long long n, int xs){  // xs : 系数int m = 0;           while(n){c[++m] = n % 10;n /= 10;}reverse(c + 1, c + 1 + m); // 3 2 4for(int i = 1; i <= m; ++i){// pos < ifor(int j = 1; j < i; ++j)ans[c[j]] += xs * c[i] * f[m - i];// pos = iif(i != 1 && c[i]) // c[i]的意思是c[i]这个数比0大  因为范围是  [0,c[i]),所以c[i]比0大,才考虑给0做贡献ans[0] += xs * f[m - i];for(int j = 1; j < c[i]; ++j)ans[j] += xs * f[m - i];// pos > iif(m > i){if(i != 1)ans[0] += xs * c[i] * f[m - i - 1] * (m - i);for(int j = 1; j < 10; ++j)ans[j] += xs * c[i] * f[m - i - 1] * (m - i);}}// 单独考虑第一类情况时,0的个数有多少个// 统计0的个数时,如果不单独考虑第一类的话,前导0也会被记入。  0000 - 9999   其实是 0 - 9999if(m > 1)ans[0] += xs * (c[1] - 1) * f[m - 2] * (m - 1);// 第1位非 0 的数字在第 j 位for(int j =  2; j < m ; ++j)ans[0] += xs * 9 * f[m - j - 1] * (m - j);
}int main(){f[0] = 1;for(int i = 1; i < 17; ++i)f[i] = f[i - 1] * 10;  // 存幂scanf("%lld%lld",&l,&r);calc(r + 1, 1);calc(l, -1);for(int i = 0; i <= 9 ; ++i)printf("%lld ", ans[i]);cout<<endl;return 0;
}

2、不要62


// 不要62
// #include <bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
ll l, r, f[20][2];
int c[21];ll calc(ll n){int m = 0;memset(c,0,sizeof(c));while(n){c[++m] = n % 10;n /= 10;}reverse(c + 1, c + 1 + m);bool ok = true;ll res = 0;for(int i = 1; i <= m && ok; ++i){for(int j = 0; j < c[i]; ++j){memset(f,0,sizeof(f));if(j == 4 || (c[i - 1] == 6 && j == 2))continue;if(j == 6)f[i][1] = 1; // 前i位,第i位为6  则第二维为1elsef[i][0] = 1;for(int k = i + 1; k <= m; ++k)for(int sign = 0; sign < 2; ++sign)if(f[k - 1][sign])for(int l = 0; l < 10; ++l){if(l == 4 || (sign && l == 2))continue;if(l == 6)f[k][1] += f[k - 1][sign]; elsef[k][0] += f[k - 1][sign]; }res += f[m][0] + f[m][1];}if(c[i] == 4 || (c[i - 1] == 6 && c[i] == 2))ok = false;}return res;
}
int main(){while(~scanf("%lld %lld",&l, &r)){if(l == 0 && r == 0)break;cout << calc(r + 1) - calc(l) << endl;}return 0;
}

3、数数1

// 数数 1#include<bits/stdc++.h>
using namespace std;#define ll long long
ll l, r, f[21][10][2];
int c[21];inline ll calc(ll n){// 计算[1,n]满足条件的个数if(!n)return 0;// n如果等于0 , 满足条件个数为0int m = 0;while(n){c[++m] = n % 10;n /= 10;}reverse(c + 1, c + 1 + m);bool ok = true;ll res = 0;for(int i = 1; i <= m && ok; ++i){// 第 i 类, 前 i - 1 位的数位值已经固定for(int j = 0; j < c[i]; ++j){// 第i位的值为jif(i != 1 && abs(j - c[i - 1]) > 2)continue;// 对于这部分的初始化问题,其实是这样的。/*比如说计算  12345 这个数字有多少是满足条件的,又比如说我们此时i = 3所以我们的j的取值范围是[0,2]当j = 0时:120 这个三位数是一个满足条件的数。所以f[3][0][1] = 1;此后的k 可以取到 4, 5 ,也就是说还要填 4,5这两个坑。而3这个位置的数可能取到[0,9]且sign可能是 0 , 1    这里的for循环只是罗列出很多的可能条件,可能很多是冗余的,但我们就是全部都考虑到了,冗余(不满足的部分)会因为判断条件而过滤掉*/memset(f,0,sizeof(f));if(i == 1 && !j)f[1][0][0] = 1;elsef[i][j][1] = 1;for(int k = i + 1; k <= m; ++k){// 后续还有 这么多个坑要填for(int l = 0; l < 10; ++l){// 前一位的数字的取值范围可能是[0,9]for(int sign = 0; sign < 2; ++sign){// 我们填写第k位时,是基于第k-1位满足条件的基础上!if(f[k - 1][l][sign]){ // 自己写的时候给漏了!!!for(int x = 0; x < 10; ++x){ //k 这个坑可以填的数字的范围是[0,9]if(sign && abs(x - l) <= 2)f[k][x][1] += f[k-1][l][1];if(!sign){if(x)f[k][x][1] += f[k - 1][0][0];elsef[k][0][0] += f[k - 1][0][0];}}}}}}for(int i = 0; i < 10; ++i)res += f[m][i][1];}// 如果出现125XXX  这样的情况, 因为后续的计算是基于前i为依据固定了的// 所以,后面的数字肯定不满足条件。  这是一个剪枝操作! 去掉的话,结果也是对的。if(i != 1 && abs(c[i] - c[i-1]) > 2)ok = false; }if(ok)res++;return res;
}
int main(){scanf("%lld%lld",&l, &r);printf("%lld\n",calc(r) - calc(l - 1));return 0;
}

4、数数2

// 数数 2#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll l, r, f[20][201];
bool b[201];
int c[21];
ll calc(ll n){ // 计算[1,n)符合条件的int m = 0;while(n){c[++m] = n % 10;n /= 10;}reverse(c + 1, c + 1 + m);ll res = 0;int sum = 0;for(int i = 1; i <= m; ++i){for(int j = 0; j < c[i]; ++j){memset(f,0,sizeof(f));f[i][sum + j] = 1;for(int k = i + 1; k <= m; ++k)for(int l = 0; l <= (k - 1) * 9; ++l)if(f[k - 1][l])for(int x = 0; x < 10; ++x)f[k][l + x] += f[k - 1][l];for(int k = 2; k <= 9 * m; ++k)if(!b[k])res += f[m][k];}sum += c[i];}return res;
}int main(){// ture : 合数   false : 质数memset(b,false,sizeof(b));b[1] = true;for(int i = 2; i <= 200; ++i){if(!b[i])for(int j = i + i; j <= 200; j += i)b[j] = true;}cin >> l >> r;cout << calc(r + 1) - calc(l) << endl;	return 0;
}

5、数数3


// 数数 3
#include <bits/stdc++.h>
using namespace std;
#define ll long long
// f[i][j][k][0..1] : 考虑了前 i 位,第 i 位的数字为 j ,前 i 位的状态为 k ,前 i 为是否全为0
// 0 这个状态表示
ll l, r, f[20][10][3][2]; 
int c[21];int get_status(int status, int x, int y){if(status == 2)return 2;if(x >= y)return 0;return status + 1;
}
ll calc(ll n){int m = 0;memset(c, 0 , sizeof(c));while(n){c[++m] = n % 10;n /= 10;}reverse(c + 1, c + 1 + m);ll res = 0;int status = 0; // 表示前 i - 1 位的状态for(int i = 1; i <= m; ++i){for(int j = 0; j < c[i]; ++j){int ns = get_status(status,c[i - 1], j); // next_status;if(i == 1)ns = 0;memset(f, 0, sizeof(f));if(i == 1 && j == 0)f[i][j][0][0] = 1;elsef[i][j][ns][1] = 1;for(int k = i + 1; k <= m; ++k){for(int w = 0; w < 10; ++w){ // 前一个数的数字范围for(int l = 0; l < 3; ++l){ // 前一个数的 状态可能for(int q = 0; q < 2; ++q){ // 前一个数 是否全为0 的情况可能if(f[k - 1][w][l][q]){for(int x = 0; x < 10; ++x){if(q == 0 && x == 0)f[k][0][0][0] += f[k - 1][0][0][0];else{if(q)f[k][x][get_status(l, w, x)][1] += f[k - 1][w][l][q];elsef[k][x][0][1] += f[k - 1][w][l][q];}}}}}}}for(int k = 0; k < 10; ++k)res += f[m][k][2][1];}if(i == 1)status = 0;elsestatus = get_status(status,c[i - 1], c[i]);}return res;}
int main(){cin >> l >> r;cout<< calc(r + 1) - calc(l) << endl;return 0;
}


http://chatgpt.dhexx.cn/article/ghHGyA7U.shtml

相关文章

数位DP 详解+模版

首先清楚数位DP要解决什么样的问题&#xff1a; 求出在给定区间 [A,B] 内&#xff0c;符合条件 f(i) 的数 i 的个数。条件 f(i) 一般与数的大小无关&#xff0c;而与数的组成有关。由于数是按位dp&#xff0c;数的大小对复杂度的影响很小。 用记忆化搜索来实现。 先来看模板…

数位DP~

综述 数位DP的应用范围&#xff1a; 在某个区间内有多少个满足一定的性质 数位DP中使用的方法&#xff1a; 类似于前缀和。A到B相当于f[B] - a[A-1] 这一点尤为重要&#xff0c;因为已经弱化了边界&#xff0c;使得考虑的更少分情况讨论 ​ 1081. 度的数量 ​ 输入样例…

数位dp(模板)

数位dp问题题型往往是这样的&#xff1a; 给定一个区间[L,R]&#xff0c;求这个区间中满足“某种条件”的数的总数。 题目&#xff1a;求区间[L,R]范围内有多少带3的数&#xff0c;所谓带3的数就是这个数十进制表示中存在至少一位3 比如3,&#xff0c;123,3333,都是带3的数&…

数位DP讲解

转载自&#xff1a;http://www.cnblogs.com/itlqs/p/5935308.html 数位DP其实是很灵活的&#xff0c;所以一定不要奢求一篇文章就会遍所有数位DP的题&#xff0c;这一篇只能是讲清楚一种情况&#xff0c;其他情况遇到再总结&#xff0c;在不断总结中慢慢体会这个思想&#xff0…

数位dp入门详解

基础篇 数位dp是一种计数用的dp&#xff0c;一般就是要统计一个区间[le,ri]内满足一些条件数的个数。所谓数位dp&#xff0c;字面意思就是在数位上进行dp咯。数位还算是比较好听的名字&#xff0c;数位的含义&#xff1a;一个数有个位、十位、百位、千位......数的每一位就是数…

数位dp。

一&#xff0c;思想&#xff1a; 在处理1e9甚至1e18,1e100的问题时&#xff0c;因为在统计情况下有很多重复的计算&#xff0c;数位dp实现了相同状态只计算一次&#xff0c;从而大幅减少运算时间&#xff0c;思想就是对每一位进行dp&#xff0c;计算时记忆化每一位可以有的状态…

【进阶】数位DP详解

如果想了解更多内容&#xff0c;欢迎关注我的微信公众号&#xff1a;信息学竞赛从入门到巅峰。 戳这里获得更好的阅读体验哦 https://mp.weixin.qq.com/s/eZHoI7RZOvlEhhSNRpGhxA 今天&#xff0c;我向大家介绍一种特殊的DP类型——数位DP。 数位DP这类题目一般不会出现在提高…

超详细讲解数位DP

什么是数位dp 数位dp是一种计数用的dp&#xff0c;一般是要统计一个区级[l,r]内满足一些条件的数的个数 所谓数位dp&#xff0c;就是对数位进行dp&#xff0c;也就是个位、十位等 相对于普通的暴力枚举&#xff0c;数位dp快就快在它的记忆化&#xff0c;也就是说后面可能会利…

数位DP,看这一篇就足够了!

数位DP用来解决什么问题&#xff1f; 我们有时候会遇到这样一类题目&#xff0c;给你一个区间 [l,r] &#xff0c;找区间上符合某种特定要求的数的个数&#xff0c;这个要求可能很简单&#xff0c;很好理解&#xff0c;但是由于区间范围太大&#xff0c;以至于对每个数进行遍历…

数位dp介绍

不了解dp的可以先看一下dp 数位dp含义&#xff1a; 数位&#xff1a;一个数有个位&#xff0c;十位&#xff0c;百位&#xff0c;千位等等&#xff0c;数的每一位都是数位。 数位dp归为计数dp&#xff0c;是在数位上进行操作的dp。 数位dp的实质是一种快速枚举的方式&#xff0…

动态规划——数位dp

数位dp 文章目录 数位dp概述题目特征基本原理计数技巧 模板例题度的数量思路代码 数字游戏思路代码 不要62思路代码 概述 数位是指把一个数字按照个、十、百、千等等一位一位地拆开&#xff0c;关注它每一位上的数字。如果拆的是十进制数&#xff0c;那么每一位数字都是 0~9&am…

数位DP学习整理(数位DP看完这篇你就会了)

文章目录 数位DP数位DP介绍数位DP解法数位DP经典例题例题1&#xff1a;度的数量例题2&#xff1a;计数问题例题3&#xff1a;数字游戏例题4&#xff1a;windy数例题5&#xff1a;数字游戏Ⅱ例题6&#xff1a;不要62例题7&#xff1a;恨7不成妻 数位DP总结 数位DP 数位DP介绍 …

Mysql悲观锁和乐观锁区别

1、mysql悲观锁&#xff1a;在整个数据处理过程中&#xff0c;将数据处于锁定状态。悲观锁的实现&#xff0c;依靠数据库提供的锁机制&#xff0c;每次会申请锁并加锁和解锁操作 第一步&#xff1a;两个终端均关闭自动提交 左边&#xff1a; 右边&#xff1a; 第二步&#xff1…

java的乐观锁和悲观锁

参考&#xff1a; https://www.cnblogs.com/jyroy/p/11365935.html https://www.jianshu.com/p/ae25eb3cfb5d 乐观锁和悲观锁 乐观锁和悲观锁是一种广义上的概念&#xff0c;体现了看待线程同步的不同角度。 乐观锁&#xff1a;对于并发操作产生的线程安全问题持乐观态度&…

MySQL中悲观锁和乐观区别

1、概念不同 乐观锁( Optimistic Locking)&#xff1a; 顾名思义&#xff0c;对加锁持有一种乐观的态度&#xff0c;即先进行业务操作&#xff0c;不到最后一步不进行加锁&#xff0c;"乐观"的认为加锁一定会成功的&#xff0c;在最后一步更新数据的时候再进行加锁…

PyQt5 - 双QTimer实现并行输出

QTime的使用 双Qtime的实现原理 一&#xff1a;QTime的使用 # -*- coding: utf-8 -*-# Form implementation generated from reading ui file D:\Qt\QT-Projects\UI项目\时间实时更新.ui # # Created by: PyQt5 UI code generator 5.12.2 # # WARNING! All changes made in t…

QTimer 定时器

QTimer类为我们提供了一个即可重复触发又可单次触发的定时器。它是一个高层次的应用程序接口。要使用它&#xff0c;只需创建一个QTimer类对象&#xff0c;将它的timeout&#xff08;&#xff09;信号连接到适当的函数上&#xff0c;然后调用其start&#xff08;&#xff09;函…

QTimer使用

QTimer工作流程 程序示例 test_timee.h //继承QObject&#xff0c;使用信号/槽 class TestTimer: public QObject {Q_OBJECT public:TestTimer(QObject *parent nullptr);public slots:void start();void stop();void do1();private://定义timer对象QTimer m_timer; }; tes…

定时器QTimer

学习PyQt推荐大家看这本书&#xff1a;https://weread.qq.com/web/reader/6393267071ccfa97639f573 链接&#xff1a;https://pan.baidu.com/s/1ZuHxNvEYtUqzSWqytN7viw 提取码&#xff1a;qku8 import sys from PyQt5.QtWidgets import QApplication,QWidget from PyQt5 i…

Qt QTimer定时器

1.QTimer简介 QTimer 主要的属性是 interval&#xff0c;是定时中断的周期&#xff0c;单位毫秒。QTimer 主要的信号是 timeout()&#xff0c;在定时中断时发射此信号&#xff0c;要想在定时中断里做出响应&#xff0c;这就需要编写 timeout() 信号的槽函数。 2.常用API //设…