这个的大意是给你一个区间,问你这个区间内的数的二进制表示中0的数量大于等于1的数量的数有多少个。
在数位DP中用s记录0比1多多少个,因为有可能1比0多,所以可以用50表示0。注意这题要标记他当前的零是否为前导零,如果是前导零的话,不能计入s中。
(数位DP比较详细的讲解见我博客hdu2089题)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define endl '\n'
using namespace std;
int a[100];
long long dp[100][100][2];
long long dfs(int len,int s,int fp,int pre)//pre==0时证明有前导零
{
if(!len)
return s >= 50;
if(!fp && dp[len][s][pre] != -1)
return dp[len][s][pre];
long long res = 0;
int n = fp?a[len]:1;
for(int i=0;i<=n;i++)
{
if(i == 0)
{
if(pre == 0)
res += dfs(len-1,s,fp && i == n,0);
else
res += dfs(len-1,s + 1,fp && i == n,1);
}
else
res += dfs(len-1,s-1,fp && i == n,1);
}
if(!fp)
dp[len][s][pre] = res;
return res;
}
long long sum(int x)
{
int len = 0;
while(x)
{
a[++len] = x % 2;
x /= 2;
}
return dfs(len,50,1,0);
}
int main(void)
{
memset(dp,-1,sizeof(dp));
int a,b;
while(scanf("%d%d",&a,&b)==2)
{
cout << sum(b) - sum(a-1) << endl;
}
return 0;
}