挺有意思的一个题目。
说白了,就是给定一个数字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; }