主要分3种情况:
1.长度比n的2进制表示的长度要小,形如:1xxxxx的格式(首位=1)
2.n能不能满足
3.长度=n的2进制表示,但从某一位开始比n小
知识点:
利用杨辉三角预处理组合数
思想:
分类考虑
前缀和

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
ll C[40][40];
void init()//预处理出组合数
{
    for(int i=0;i<=35;i++)
    {
        C[i][0]=C[i][i]=1;
        for(int j=1;j<i;j++)
            C[i][j]=C[i-1][j-1]+C[i-1][j];
    }
}
ll solve(int n)
{
    if(n==0)
        return 0;
    int tn=n,len=0;
    int bn[40]={0},sum0[40]={0};
    while(tn)
    {
        bn[++len]=tn%2;
        tn>>=1;
    }
    ll res=0;
    for(int i=1;i<=len;i++)
        sum0[i]=sum0[i-1]+(bn[i]==0);
    for(int i=1;i<len;i++)//第一类1xxxxx(长度小于len)
    {
        for(int j=(i+1)/2;j<i;j++)
            res+=C[i-1][j];
    }
    if(sum0[len]>=len-sum0[len])//第二类(n本身就满足)
        res++;//cout<<"2:"<<res<<endl;
    //第三种长度为len,但从某一位开始小于n,但不能是最高位,目的使长度不变的情况下,使之满足条件
    int m0=(len+1)/2;//要使n为满足条件的数,应该保证含有的0的最小值
    for(int i=1;i<len;i++)//<len:保证长度==len
    {
        if(bn[i]==1)//枚举除最高位以外的为1的位置,作为开始小于n的位置
        {
            int tmp=sum0[len]-sum0[i]+1;//原来共sum0[len]个0,要满足要求,整个式子0的个数>=m0,对于1~i的范围内,
            //把i位置的1边成0后,还有i-1个位置可以自由取值,只要能够让1~i-1和i+1~n范围内的0的个数达到要求即可
            int tol=i-1;//总的位置数
            for(int j=max(0,m0-tmp);j<=tol;j++)//使0的个数达到要求所需要的最少的0的个数~位置数目
                res+=C[tol][j];//cout<<"res="<<res<<endl;
        }
    }//cout<<"res="<<res<<endl;
    return res;
}
int main()
{
    int s,f;
    init();
    while(scanf("%d%d",&s,&f)!=EOF)
    {
        ll ans=solve(f)-solve(s-1);
        printf("%lld\n",ans);
    }
    return 0;
}