挺有意思的一个题目。
说白了,就是给定一个数字K, 我能否计算出从0~K 这K+1个数字中(全部用二进制表示), 有几个数字是有1个1,有几个数字是2个1,有几个数字有3个1, 有几个数字有4个1……
这样的问题可以看成是, 有T个空格,我有K个1要插入这T个空格中。 这样的话,这个问题就转化为组合数学问题了。
举个例子:
对于一个二进制数字 11010
我们可以看成是10000 + 1000 + 000 + 10 + 0
分成 0~ 10000 , 10000~ 11000, 11000~ 11010 这3个部分来计算
实际上也就是0~10000, 0~1000, 0 ~10 这3个部分~!
因为我要求10000~11000之间,有多少个数字,是有【3】个1的。 实际上是求0~1000之间,有多少个数字,是有【2】个1的。 【这句话要好好理解】
========
那么问题就简单了,把一个二进制数字拆开看,分别用组合数学的知识求出来即可。对于二进制数字拆分成10000+1000+000+10+0的方法,可以用lowbit的方法来解决。 具体程序写的挺清楚的。(deep是计算层数, 因为上面那个让好好理解的那句话, 1的位置越靠后,需要计算的数量越少。)
至于lowbit的原理和应用,可以参考我博客里一篇关于树状数组的介绍。
=====
上面这段话没看懂? 没事, 自己了解一下lowbit这个东西的含义…… 然后其实提示这么多,一般也应该会做了…… 程序速度还算优秀
可以用一个函数cal(a,b) 表示从0~b之间, 有0~a个1组成,所产生的方案总数。 这样题目就变为一个判定性问题,二分答案即可。
Compiling... Compile: OK Executing... Test 1: TEST OK [0.003 secs, 3380 KB] Test 2: TEST OK [0.003 secs, 3380 KB] Test 3: TEST OK [0.003 secs, 3380 KB] Test 4: TEST OK [0.003 secs, 3380 KB] Test 5: TEST OK [0.005 secs, 3380 KB] Test 6: TEST OK [0.011 secs, 3380 KB] Test 7: TEST OK [0.008 secs, 3380 KB] Test 8: TEST OK [0.005 secs, 3380 KB] Test 9: TEST OK [0.008 secs, 3380 KB] Test 10: TEST OK [0.003 secs, 3380 KB] Test 11: TEST OK [0.003 secs, 3380 KB] Test 12: TEST OK [0.003 secs, 3380 KB] Test 13: TEST OK [0.005 secs, 3380 KB] All tests OK.
/*
TASK:kimbits
LANG:C++
*/
#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;
#define lowbit(k) ((k)&(-k))
typedef long long LL;
LL N,L,I;
LL c[33][33]={0};
int a[33]={0};
int deep;
LL cal(int k, LL tot)
{
if (!tot) return 1;
LL tmp = log(lowbit(tot)) / log(2.0);
LL ret = cal(k, tot - lowbit(tot));
++ deep;
for (int i = 0; i <= k - deep; ++ i) ret += c[tmp][i];
return ret;
}
inline void pg(LL k)
{
int son[50]={0}, len = N;
while (k)
{
son[len--] = k % 2;
k /= 2;
}
for (int i = 1; i <= N; ++ i) cout<<son[i];
cout<<endl;
}
int main()
{
freopen("kimbits.in","r",stdin);
freopen("kimbits.out","w",stdout);
for (int i = 0; i != 33; ++ i) c[i][0] = 1;
for (int i = 1; i != 33; ++ i)
for (int j = 1; j <= i; ++ j) c[i][j] = c[i - 1][j - 1] + c[i - 1][j]; //计算组合数
cin >> N >> L >> I;
int p = I, tmp;
LL low= 0, up = 2300000000LL;
while (low + 1 < up) //[ )
{
deep = -1;
LL mid = (low + up) >> 1;
LL tmp = cal(L, mid);
if (tmp > I) up = mid;
else low = mid;
}
pg(low);
return 0;
}