#lydlx05x0E19. 圆形数字 Round Numbers
圆形数字 Round Numbers
题目描述
定义圆形数字如下:
把一个十进制数转换为一个无符号二进制数,若该二进制数中 0 的个数大于或等于 1 的个数,则它就是一个圆形数字。
现在给定两个正整数 和 ,请问在区间 内有多少个圆形数字。
输入格式
输入占一行,包含两个整数 和 。
输出格式
输出一个整数,表示圆形数字的个数。
样例
2 12
6
样例解释
输入
,
需要检查的数字
区间 内的整数:2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
转换为二进制并判断
- 2: 二进制
10,0 的个数 1,1 的个数 1,0≥1,是圆形数字。 - 3: 二进制
11,0 的个数 0,1 的个数 2,0<2,不是。 - 4: 二进制
100,0 的个数 2,1 的个数 1,2≥1,是。 - 5: 二进制
101,0 的个数 1,1 的个数 2,1<2,不是。 - 6: 二进制
110,0 的个数 1,1 的个数 2,1<2,不是。 - 7: 二进制
111,0 的个数 0,1 的个数 3,0<3,不是。 - 8: 二进制
1000,0 的个数 3,1 的个数 1,3≥1,是。 - 9: 二进制
1001,0 的个数 2,1 的个数 2,2≥2,是。 - 10: 二进制
1010,0 的个数 2,1 的个数 2,2≥2,是。 - 11: 二进制
1011,0 的个数 1,1 的个数 3,1<3,不是。 - 12: 二进制
1100,0 的个数 2,1 的个数 2,2≥2,是。
圆形数字有:2, 4, 8, 9, 10, 12,共 6 个。
数据范围
算法分析
这是一个数位统计 DP问题,需要统计区间 内满足二进制表示中 0 的个数 ≥ 1 的个数的数的个数。
由于 最大 ,二进制位最多 31 位(因为 )。
问题转化
设 表示 中圆形数字的个数,则答案 = 。
因此,我们需要实现函数 。
数位 DP
通常数位 DP 针对十进制,这里二进制类似。但注意“无符号二进制数”不包含前导零,但统计 0 的个数时,前导零不计入(因为无符号二进制表示没有前导零)。例如,数字 2 的二进制是 10,不是 0010。
所以我们需要统计的是有效二进制位中 0 和 1 的个数。
设 表示当前处理到第 位(从高位到低位),已经填的 0 的个数为 ,1 的个数为 , 表示是否受到 的限制(即之前填的位是否与 的对应位相同)。
但这样状态数: 最多 31, 和 最多 31,状态数 ,可接受。
转移时,枚举当前位填 0 或 1(注意不能有前导零,所以最高位必须填 1)。如果当前位填 0,则 ;填 1,则 。
最终,当所有位填完后,如果 ,则该数合法。
注意
- 数字 0 需要特殊处理:二进制表示
0,0 的个数 1(只有一位 0),1 的个数 0,,所以 0 是圆形数字。但题目给定 ,所以可以不考虑 0。 - 最高位必须为 1,所以从最高位开始填 1。
优化
由于 和 的和等于已填位数,所以可以只记录 和 的差值 ,这样状态减少一维。但 范围 ,需要加偏移量。
设 ,其中 ,偏移量 (因为最多 31 位)。状态数 ,更小。
转移:填 0 则 ,填 1 则 。
最终,如果 ,则合法。
实现步骤
- 将 转换为二进制字符串(不含前导零)。
- 记忆化搜索 :
- :当前处理到第几位(从 0 开始)。
- :当前 0 的个数减去 1 的个数。
- :是否受到 的限制(即前面填的位是否与 相同)。
- 如果 达到二进制长度 ,则返回 。
- 枚举当前位填的数字 (0 或 1):
- 如果 为真,则 不能超过 的第 位。
- 如果 (即最高位),必须填 1。
- 递归计算,累加结果。
- 使用记忆化数组存储结果,注意 可能为负,需要加偏移量。
边界情况
- 数字 0 需要单独判断(如果 ,则返回 1)。但题目 ,所以不需要。
- 注意 初始值:开始填之前,没有 0 和 1,所以 。
样例验证
对于 ,计算 :
二进制:1100,长度 4。
搜索过程:
- 最高位必须填 1,。
- 第二位可以填 0 或 1(受限制? 的第二位是 1,所以如果前面填的与 相同,则不能超过 1;否则可以填任意)。 最终统计所有合法路径。
结果 (1,2,4,8,9,10,12 中圆形数字有 2,4,8,9,10,12,共 6 个)。
(数字 1 的二进制 1,0 个 0,1 个 1,不是圆形数字)。
所以 的圆形数字个数 = 。
复杂度
状态数 ,位数最多 31,差值范围 ,共约 ,每次转移 ,总计算量很小。
总结
本题是二进制数位 DP,关键点:
- 无前导零,最高位必须为 1。
- 用差值 代替 和 减少状态。
- 记忆化搜索实现。