题目:http://www.nocow.cn/index.php/Translate:USACO/kimbits
求出可以用<=K个1表示的长度为N的二进制串的最小的第I个数。又是01字符串,最先想到方法是遍历1~2^N-1的自然数,如果其中包含1的个数<=K个1表示,则计数加1,直到I为止。但是想想2^31次方可以表示接近2 0000000000的整数,肯定会超时的。
如果把二进制串当作二叉树的叶子节点,然后采用前序遍历的方式对二叉树进行遍历,往左边走,1的个数不变,往右边走,1的个数加1,满足条件的叶子节点,计数器加1,同时对二叉树进行剪枝。
(1)当1的个数>K的子树,可以剪枝。
(2)当K - 1的个数 >= N - 深度,证明剩下的位数可以从全0到全1排满,而此时如果 计数器 + 2 ^ (N - 深度) < I,则计数器直接+ 2 ^ (N - 深度),跳过这个子树。这一步是很关键的。
(3)如果N <= K,第I小的数为I-1
(4)如果I <= 2^K -1,则最小数为 I -1
上面四个剪枝,前两个最为关键,代码如下:
顺利通过了USACO的测试,速度还不错,测试结果如下: