一道数位DP好题

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#define gc getchar()
using namespace std;
inline void qr(int &x)
{
    x=0;char c=gc;int f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
    while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
    x*=f;
}
void qw(int x)
{
    if(x<0)x=-x,putchar('-');
    if(x/10)qw(x/10);
    putchar(x%10+48);
}
int c[33][33];bool v[50];
inline int sum(int n,int m)
{
    int ans=0;
    for(int i=m;i<=n;i++)
        if(2*i>=n+m)ans+=c[n][i];//1的数量少1,0的数量就多1,之差就缩小2 
    return ans;
}
int calc(int x)
{
    int d=1,len=0,ans=0;
    while(x)v[++len]=x&1,x>>=1;
    for(int i=1;i<len;i++)ans+=sum(i-1,1);//最高位是0,不允许有前导0,那么枚举数的位数,数最高位一定是1 
    --len;//最高位确定是1 
    while(len) 
    {
        if(v[len])ans+=sum(len-1,d-1),++d;//当前这一位是1,那么就可以枚举这一位是0的情况了。 
        else --d; 
        --len;
    }
    if(d<=0)++ans;//这个数本身就合法。 
    return ans;
}
int main()
{
    memset(v,0,sizeof(v));
    for(int i=1;i<=32;i++)
    {
        c[i-1][0]=1;
        for(int j=1;j<=i;j++)
            c[i][j]=c[i-1][j-1]+c[i-1][j];
    }
    int l,r;qr(l),qr(r);
    if(l>2)qw(calc(r)-calc(l-1));else qw(calc(r));
    puts("");
    return 0;
}