浅谈数位类问题 刘聪
第 3页,共 12 页
x=x^(1<<i);
}
if ((1<<(i-1))<=x) {
ans+=f[i-1][k-tot];
}
}
if (tot+x==k) ++ans;
return ans;
}
最后的问题就是如何处理非二进制。对于询问 n,我们需要求出不超过 n 的最大 B 进制
表示只含 0、1 的数:找到 n 的左起第一位非 0、1 的数位,将它变为 1,并将右面所有数位
设为 1。将得到的 B 进制表示视为二进制进行询问即可。
预处理递推 f 的时间复杂度为 O(log
2
(n)),共有 O(log(n))次查询,因此总时间复杂度为
O(log
2
(n))。
实际上,最终的代码并不涉及树的操作,我们只是利用图形的方式来方便思考。因此也
可以只从数位的角度考虑:对于询问 n,我们找到一个等于 1 的数位,将它赋为 0,则它右
面的数位可以任意取,我们需要统计其中恰好含有 K-tot 个 1 的数的个数(其中 tot 表示这
一位左边的 1 的个数),则可以利用组合数公式求解。逐位枚举所有”1”进行统计即可。
我们发现,之前推出的 f 正是组合数。同样是采用“逐位确定”的方法,两种方法异曲
同工。当你觉得单纯从数位的角度较难思考时,不妨画出图形以方便思考。
【例题 2】Sorted bit sequence (spoj 1182)
题目大意:
将区间[m,n]内的所有整数按照其二进制表示中 1 的数量从小到大排序。如果 1 的数量
相同,则按照数的大小排序。求这个序列中的第 k 个数。其中,负数使用补码来表示:一个
负数的二进制表示与其相反数的二进制之和恰好等于 2
32
。
例如,当 m=0,n=5 时,排序后的序列如下:
编号 十进制数 二进制表示
1 0
0000 0000 0000 0000 0000 0000 0000 0000
2 1
0000 0000 0000 0000 0000 0000 0000 0001
3 2
0000 0000 0000 0000 0000 0000 0000 0010
4 4
0000 0000 0000 0000 0000 0000 0000 0100
5 3
0000 0000 0000 0000 0000 0000 0000 0011
6 5
0000 0000 0000 0000 0000 0000 0000 0101
当 m=-5,n=-2 时,排序后的序列如下:
编号 十进制数 二进制表示
1 -4
1111 1111 1111 1111 1111 1111 1111 1100
2 -5
1111 1111 1111 1111 1111 1111 1111 1011
3 -3
1111 1111 1111 1111 1111 1111 1111 1101
4 -2
1111 1111 1111 1111 1111 1111 1111 1110