6
题目意思:
给定一个2 * 10^9范围内的一个范围L,R 让你在这个范围内有多少个十进制数字中的二进制0的个数大于等于1的个数
题解:
可以设定一个get_prefix(int n)的函数,也就是求出从1---->n中有多少个二进制0的个数大于等于1的个数的合
法数字,然后减一下就可以。
具体求的方法是,把n转换为2进制,假设为n的二进制一共有len这么长,先不考虑n的二进制最高位,即只考虑剩下的
len-1位,当长度为len-1时,最高位为1,剩下的便是一个计数组合问题了,放多少个0是合法的,即1XXXXX....
具体的例子借鉴一下Bin神题解的例子是22
拆为二进制为 22 = 1 0 1 1 0 len = 5
去除最高位的1,
当len = 4的时候,最高位为1,即1XXX,有三个位置可以放,可以放0也可以放1,合法的放法是2个0或3个0(算上最
高位的1),即有C(3,2) + C(3,3) = 4
同理,len = 3的时候,最高位为1,即1XX,有两个位置可以放,有C(2,2) = 1
同理,len = 2的时候,有C(1,1) = 1
剩下要解决的便是len = 5的时候的,要根据n的二进制去遍历n的二进制数组,当较高位为0的时候可以略过,担当最高
位为1的时候就可以把1换为0了.
具体见代码
#include <algorithm>
#include <iostream>
#include <numeric>
#include <cstring>
#include <iomanip>
#include <string>
#include <vector>
#include <cstdio>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
#include <set>
#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const LL MAX = 405;
const double esp = 1e-6;
const double PI = 3.1415926535898;
const int INF = 0x3f3f3f3f;
using namespace std;
LL dp[40][40];
void init(){
memset(dp,0,sizeof(dp));
for(int i=0;i<=35;i++)
dp[i][i] = dp[0][i] = dp[1][i] = 1;
for(int i=0;i<=35;i++)
dp[i][0] = 1;
for(int i=1;i<=35;i++){
for(int j=1;j<=35;j++){
if(i != j)
dp[i][j] = dp[i-1][j] + dp[i-1][j-1];
}
}
}
LL cal(LL n){
if(n <= 1)
return 0;
LL two[40],t = 0,m = n,zero = 0,one = 0;
while(m){
two[t++] = m%2;
if(m%2)
one += 1;
else
zero += 1;
m /= 2;
}
LL ans = 0;
for(int i = t - 1;i > 0;i--){
if(i%2)
ans += ((1<<(i-1)) - dp[i-1][(i-1)/2]) / 2;
else
ans += ((1<<(i-1))) / 2;
}
if(zero >= one)
ans += 1;
zero = 0;one = 1;
for(int i = t - 2;i >= 0;i--){
if(two[i] == 0)
zero += 1;
else{
for(int j=i;j >= 0 && j + zero + 1 >= i - j + one;j--)
ans += dp[i][j];
one += 1;
}
}
return ans;
}
int main(){
LL n,m;
init();
while(~scanf("%lld %lld",&n,&m)){
printf("%lldn",cal(m) - cal(n - 1));
}
return 0;
}
发表评论 取消回复