当前位置: 首页 > news >正文

蓝桥杯b组c++赛道---数位dp

一、定义与适用场景:

数位 DP 是一种用于解决与数字的数位相关问题的动态规划方法。适用于统计区间内满足特定条件的数字个数、计算数字范围内各位数字之和满足某种条件的最大数字等问题。例如,统计给定区间内不含数字 4 的整数个数,或者统计各位数字之和为特定值的数字个数等。


二、基本原理:

  • 状态定义:通常用 dp[i][state] 来表示状态,其中 i 表示当前处理到数字的第 i 位(从高位到低位),state 表示与数位相关的某种状态,比如前面 i 位数字的和、出现过的数字集合等。例如,要统计区间内各位数字之和为 k 的数字个数,那么 dp[i][j] 可以表示处理到第 i 位时,前 i 位数字之和为 j 的数字个数。
  • 状态转移方程:根据当前位的数字取值以及前一位的状态来确定当前状态。例如,对于统计不含数字 4 的数字个数问题,假设当前位为 i ,如果当前位不能取 4 ,那么 dp[i][state] 就等于 dp[i−1][state] (当前位取 0 到 3 )加上 dp[i−1][state′] (当前位取 5 到 9 ,这里 state′ 是根据当前位取值更新后的状态)。
  • 边界条件:一般来说,当 i=0 时,即处理到最高位之前,状态通常为初始状态。例如,对于统计数字个数的问题,初始状态 dp[0][0] 可以设为 1 ,表示空数字是一种合法的状态,而其他 dp[0][j] (j≠0 )设为 0 。

三、解题步骤:

  1. 确定状态:分析问题,确定需要用哪些变量来表示数字的状态。比如,是考虑数字的每一位之和、特定数字出现的次数,还是数字的某种排列组合情况等。
  2. 定义 dp 数组:根据确定的状态,定义 dp 数组来存储中间结果。数组的维度通常与状态变量的个数相关。
  3. 初始化 dp 数组:设置边界条件和初始状态。这是动态规划的起点,通常根据问题的具体情况来确定。
  4. 计算状态转移:从高位到低位依次枚举数字的每一位,根据当前位的取值和之前的状态,通过状态转移方程计算当前状态的值。
  5. 得到答案:根据题目要求,从 dp 数组中提取最终的答案。可能是 dp 数组中的某个特定元素,或者是对 dp 数组中多个元素的组合计算。

四、示例题目及分析:

度的数量问题描述:求给定区间[X,Y]中满足下列条件的整数个数:这个数恰好等于K个互不相等的 B 的整数次幂之和。例如,设X = 15,Y =20,K=2,B=2,则有且仅有下列三个数满足题意:
17=2^4+2^0
18 =2^4+2^1
20=2^4+2^2
输入格式
第一行包含两个整数 X和 Y,接下来两行包含整数 K 和 B
输出格式
只包含一个整数,表示满足条件的数的个数。
数据范围
1≤X ≤Y ≤ 2^31-1,
1<=K<20,
2<=B<10
输入样例:
15 20
2
2
输出样例:
3

解题思路

这个问题可以通过数位动态规划(DP)来解决。关键在于将整数转换为 B 进制表示,并统计满足条件的数字个数。

核心分析

  1. B 进制表示:每个整数 N 都可以唯一表示为 B 的不同次幂之和,即 B 进制表示。例如,17 的二进制表示为 10001,对应 2⁴ + 2⁰。

  2. 条件转换:问题转化为统计区间 [X,Y] 内的数,其 B 进制表示中恰好有 K 个 1,其余位为 0。

  3. 数位 DP 框架

    • 状态定义f[i][j]表示处理到第i位时,已经有j个 1。
    • 状态转移:枚举当前位的可能取值(0 或 1,受limit限制),并更新状态。
    • 边界条件:处理完所有位后,检查cnt是否等于 K。
  4. 前缀和思想:计算 [1,Y] 和 [1,X-1] 的结果,然后相减得到 [X,Y] 的结果。

#include<bits/stdc++.h>
using namespace std;typedef long long ll;
const int maxn=100000+5;
const int mod=1e9+9;int l,r,k,b;//区间【l,r】  k个1 b进制    转换为b进制数,有k个互不相同的数,相当于b进制数里面有k个1
int f[35][35];//整数最多32位,扩大一点防止越界//初始化组合数
void init() {for(int i=0; i<35; i++) {for(int j=0; j<=i; j++) {if(!j)f[i][j]=1;//组合数 C(i,0)=1else {f[i][j]=f[i-1][j]+f[i-1][j-1];//不填1(填0),剩余i-1位仍需填j个1   填1,剩余i-1位填j-1个1}}}
}//数位 DP 核心函数 dp
int dp(int n) {if(!n)return 0;//传进来区间为0//用vector存储进制数vector<int>num;while(n) {num.push_back(n%b);n/=b;}int res=0,last=0;//res统计区间内满足条件的个数  last记录数字里面1的个数//根据数位dp的概念 从最高位开始求取for(int i=num.size()-1; i>=0; i--) {int x=num[i];//便于后续处理//若 x=0:当前位只能填 0,无法填 1(否则超过原数),直接跳过。//若 x≥1:可以填 0 或 1,进入分支处理。if(x) {//存在左分支res+=f[i][k-last];//在当前位填 0,剩余的i位中需要选出k-last个 1//右分支:有很多种可能,此刻遍历当前位填 1的情况 if(x>1) {if(k-last-1>=0) {//左分支填 1:若当前位填 1,剩余i位中需选k-last-1个 1。res+=f[i][k-last-1];}break;} else {//当x==1就可以进入右边的分支继续讨论。last++;if(last>k)break;//说明 1 的数量已超标,直接退出}}//如果符合条件那么末位填0也算一种方案。if(!i&&last==k)res++;}return res;
}int main() {ios::sync_with_stdio(false);cin.tie(0);cin>>l>>r>>k>>b;init();cout<<dp(r)-dp(l-1)<<endl;return 0;
}

相关文章:

  • 互联网大厂Java求职面试:AI大模型与云原生架构融合中的挑战
  • Jenkins部署
  • 不打印nacos相关信息,无法进行注册nacos
  • UDP协议原理与Java编程实战:无连接通信的奥秘
  • 企业网络综合实训
  • 七彩喜认知症评估系统:解码大脑健康的“数字先知”
  • 食品检验师的职业发展路径是怎样的?
  • QAtomicInt原子变量的CAS(Compare And Swap)写法与优缺点
  • Python应用“面向对象”小练习
  • OpenOCD 与 PlatformIO
  • 010501上传下载_反弹shell-渗透命令-基础入门-网络安全
  • C++ 继承的相关内容 基类和派生类 默认成员函数的区别等问题
  • 机器学习k近邻,高斯朴素贝叶斯分类器
  • 将 Docker 镜像从服务器A迁移到服务器B的方法
  • 【Axure结合Echarts绘制图表】
  • “安康杯”安全生产知识竞赛活动流程方案
  • ATPrompt方法:属性嵌入的文本提示学习
  • 本周 edu教育邮箱注册可行方案
  • 车载通信网络 --- 传统车载网络及其发展
  • 【C++高级主题】异常处理(四):auto_ptr类
  • 企业php网站建设/培训机构招生方案模板
  • 廊坊网站建设/合肥seo按天收费
  • 网站建设net接口/线上电商怎么做
  • 聊城网站制作公司电话/郑州网络营销哪家正规
  • 多个wordpress管理系统/百度seo培训
  • 被k掉的网站怎么做才能有收录/如何制作公司网页