有这样一种集合,集合元素为长度N(1~31)的二进制串,并且每个二进制串中1的个数小于等于L,求这个集合中第I大的元素是多少?
最开始很天真的想枚举每个数,计算其中1的个数,结果第8组测试数据开始就超时的不行了。
枚举不行,来试试构造可不可以,假设我们有一个长度为n,1个数<=l的二进制串的集合,那么怎么把它们从大到小区分呢?我们一位一位来,根据第n位,可以将集合划为2部分:第n位是0的,第n为是1的。好了,递推式突然就变得很明显了。如何设num[N][L]为长度为N,1个数小于等于L的二进制串的个数,那么:
num[N][L] = num[N-1][L] + num[N-1][L-1]
(第n位是0) (第n位是1)
个数有了,那么第I个数是多少怎么求呢?说来也简单,就是用递归的思想,看I落在num[N-1][L]和num[N-1][L-1]的哪一部分,看下面的代码应该就明白了:
void Print (int len, int num1, long long idx)
{
if ( len == 0 )
return;
if ( num[len-1][num1] >= idx )
{
putchar('0');
Print(len-1, num1, idx);
}
else
{
putchar('1');
Print(len-1, num1-1, idx-num[len-1][num1]);
}
}