题目不是很难,不过因为一个细节贡献了两次wa(在计算[0, 0]上的round numbers时答案应该是0,结果算成了1)
思路就是[a, b] 上的答案等于[0, b] - [0, a - 1]。
在计算[0, k]上的round numbers时,先求位数比k的二进制小的,这些数肯定比k小,所以0和1可以任意放,用排列组合的方法很容易算。然后求和k的二进制位一样长的,从k的二进制的最高位往下求(最高位除外),遇到1就假设把这个1换成0,那么后面的数组不管放几,肯定比k小,这样就可以用排列组合的方法求这种情况下的round numbers了,扫完所有二进制位就可以了。
如果k的二进制位中0的数目本来就多余或等于1的数目,答案+1。
/*
* Author: stormdpzh
* POJ: 3252 Round Numbers
* Time: 2012/4/28 21:18:29
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <algorithm>
#include <functional>
#define sz(v) ((int)(v).size())
#define rep(i, n) for(int i = 0; i < n; i++)
#define repf(i, a, b) for(int i = a; i <= b; i++)
#define out(n) printf("%d", n)
#define wh(n) while(scanf("%d", &n) != EOF)
#define whz(n) while(scanf("%d", &n) != EOF && n != 0)
#define int64 long long
using namespace std;
int C[35][35]; //C[i][j], C(i, j);
int bin[35]; //binary number
int len; //length of binary number
void getC()
{
C[0][0] = 1;
repf(i, 1, 34) {
repf(j, 0, i) {
if(j == 0 || i == j)
C[i][j] = 1;
else
C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
}
}
}
void getBin(int num)
{
len = 0;
while(num) {
bin[len++] = num & 1;
num = num >> 1;
}
}
//solve(k): calculate round numbers of [0, k]
int solve(int key)
{
if(key <= 1)
return 0;
int res = 0;
memset(bin, 0, sizeof(bin));
getBin(key);
for(int i = 1; i < len; i++) {
repf(j, (i >> 1) + (i & 1), i - 1) {
res += C[i - 1][j];
}
}
int zero = 0;
int tmp = (len >> 1) + (len & 1);
for(int i = len - 2; i >= 0; i--) {
if(bin[i] == 1) {
repf(j, max(tmp - zero - 1, 0), i)
res += C[i][j];
}
else
zero++;
}
if(zero >= (len >> 1) + (len & 1))
res++;
return res;
}
int main()
{
int start, finish;
getC();
while(scanf("%d%d", &start, &finish) != EOF) {
printf("%d\n", solve(finish) - solve(start - 1));
}
return 0;
}