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

东方博宜OJ 2557:幂次求和 ← 数位DP

【题目来源】
https://oj.czos.cn/p/2557
https://www.acwing.com/problem/content/1083/

【题目描述】
求给定区间 [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。

【输出格式】
只包含一个整数,表示满足条件的数的个数。

【输入样例】
15 20
2
2

【输出样例】
3

【数据范围】
对于全部数据,1≤X≤Y≤2^31-1,1≤K≤20,2≤B≤10。

【算法分析】
● 本题与“AcWing 1081:度的数量”(https://www.acwing.com/problem/content/1083/)的代码完全一致。详见:https://blog.csdn.net/hnjzsyjyj/article/details/155972543

● 核心思路与预处理
(一)问题转换
题目要求统计的数字,其 b 进制表示中的每一位只能是 0 或 1,并且 1 的总数恰好为 k。这本质上是在 b 进制下,寻找所有‌二进制表示‌(但用 b 进制书写)中 1 的个数为 k 的数。
(二)组合数预处理

void init() {for(int i=0; i<N; i++)for(int j=0; j<=i; j++)if(j==0) f[i][j]=1;else f[i][j]=f[i-1][j-1]+f[i-1][j];
}

f[i][j] 表示从 i 个位置中选出 j 个位置放置 1 的组合数,即 C(i, j)。
使用‌帕斯卡公式‌(杨辉三角)递推计算:C(i, j)=C(i-1, j-1)+C(i-1, j)。
这个组合数数组是后续计算的核心工具。

● 核心计算函数 dp(int n)
(一)数位分解

vector<int> v;
while(n) {v.push_back(n%b);n/=b;
}

将数字 n 转换为 b 进制表示,v[0] 存储最低位,v[v.size()-1] 存储最高位。
(二)逐位统计逻辑

int cnt=0,pre=0;
for(int i=v.size()-1; i>=0; i--) {int x=v[i];if(x>0) {cnt+=f[i][k-pre];if(x>1) {if(k-pre-1>=0) cnt+=f[i][k-pre-1];break;} else {pre++;if(pre>k) break;}}if(i==0 && pre==k) cnt++;
}

变量说明:‌
cnt:累计满足条件的数字个数。
pre:已经确定的 1 的个数(在前面的高位中)。
i:当前处理位的位置索引(从最高位向最低位)。
x:当前位的值(在 b 进制下)。
处理逻辑详解:‌
(1) 当前位 x>0 的情况

cnt+=f[i][k-pre];

如果当前位取 0:那么剩余的 i 个低位中,需要放置 k-pre 个 1。
这种情况的数量是 C(i, k−pre)。
(2) 当前位 x>1 的情况

if(x>1) {if(k-pre-1>=0) cnt+=f[i][k-pre-1];break;
}

如果当前位可以取 1:那么剩余的 i 个低位中,需要放置 k-pre-1 个 1。
这种情况的数量是 C(i, k−pre-1)。
break 的原因‌:由于 x>1,当前位如果取 1,已经小于原数的这一位,所以后续低位可以‌任意选择‌(只要满足总 1 数条件)。统计完这种情况后,不需要再考虑固定当前位等于 x 的情况,因为原数本身不可能满足条件(有非 0 非 1 的位)。
(3) 当前位 x==1 的情况

else {pre++;if(pre>k) break;
}

当前位必须取 1(因为原数这一位就是 1,且不能取 0,否则会超过原数范围)。
pre++:已确定的 1 数增加。
如果 pre>k:已经使用的 1 超过了限额,原数不可能满足条件,提前结束。
(4) 处理完所有位的情况

if(i==0 && pre==k) cnt++;

如果成功处理到最低位(i==0),并且整个过程中使用的 1 数恰好为 k,那么原数 n 本身也满足条件,需要计入。


【算法代码】

#include<bits/stdc++.h>
using namespace std;const int N=35; //数的位数
int f[N][N]; //f[i][j]表示在i个位置上放置j个1的组合数
int k,b;void init() {for(int i=0; i<N; i++)for(int j=0; j<=i; j++)if(j==0) f[i][j]=1;else f[i][j]=f[i-1][j-1]+f[i-1][j];
}int dp(int n) {if(n==0) return 0;vector<int> v;while(n) {v.push_back(n%b);n/=b;}int cnt=0,pre=0;for(int i=v.size()-1; i>=0; i--) {int x=v[i];if(x>0) {cnt+=f[i][k-pre];if(x>1) {if(k-pre-1>=0) cnt+=f[i][k-pre-1];break;} else {pre++;if(pre>k) break;}}if(i==0 && pre==k) cnt++;}return cnt;
}int main() {init();int le,ri;cin>>le>>ri>>k>>b;cout<<dp(ri)-dp(le-1)<<endl;return 0;
}/*
in:
15 20
2
2out:
3
*/





【参考文献】
https://blog.csdn.net/hnjzsyjyj/article/details/156048397
https://blog.csdn.net/hnjzsyjyj/article/details/156039366
https://blog.csdn.net/hnjzsyjyj/article/details/156267002
https://blog.csdn.net/hnjzsyjyj/article/details/156011817
https://blog.csdn.net/WhereIsHeroFrom/article/details/148437243
https://www.acwing.com/solution/content/245183/


 

http://www.zskr.cn/news/159755.html

相关文章:

  • 论文 “去红去机” 兵器谱:这9款工具,重复率 + AIGC 疑似度双降
  • Java毕设项目:基于微服务教材征订系统(源码+文档,讲解、调试运行,定制等)
  • 线下挑儿童羽绒服不踩坑!2025年口碑品牌实测指南(宝妈必收) - 品牌测评鉴赏家
  • 英语_阅读_tanker trucks for carrying edible oil_待读
  • 深入解析:GitHub 一周热门项目速览 | 2025年12月1日
  • 为GIT仓库项目设置独立配置参数
  • scrapy基础知识之发送POST请求
  • 如何开启第一次开源贡献之路?
  • Python返回数组/List长度的方法
  • 论文AI率卡在20%?试试这十佳降AI软件,专治各种检测不过
  • 微店商品详情API使用指南
  • 2025年儿童鞋服品牌前十名盘点:专业、舒适、潮流怎么选? - 品牌测评鉴赏家
  • 国货之光!这10+国产儿童鞋服品牌闭眼入,宝妈收藏这篇就够了 - 品牌测评鉴赏家
  • DBeaver设置不断开连接
  • 1.磁盘阵列
  • 【社交APP上线记】小夏、老周、小林的讨论组
  • 宝妈宝爸闭眼入!0 - 16岁儿童鞋服优质品牌大盘点 - 品牌测评鉴赏家
  • 城市仿真软件:CityEngine_(18).性能优化与渲染技术
  • CSS3 字体
  • 通信协议仿真:5G NR协议仿真_(13).5G NR仿真中的资源管理
  • 《告别跨端运算偏差:游戏确定浮点数学库的核心搭建指南》
  • Comsol软件下的弯曲波导模式分析及有效折射率与损耗精确计算
  • JavaScript 字符串模板
  • 学长血泪复盘:试错半个月,终于找到这十大靠谱降AI方法
  • 九尾狐AI:传统企业AI转型实战白皮书
  • 西电复试面试、笔试时间汇总!最强上岸攻略!
  • Python3 基本数据类型
  • fwrite与fflush作用
  • 【有搜必应】HarmonyOS 热搜技术问题解析第五期
  • django《Python程序设计》课程智能问答系统 智能AI客服问答系统_88mj5719