原题链接
考察:数位dp
思路:
入门题(然后做了一个小时)
这里预处理方案数是用组合数.如果我们直接套模板会发现答案不对,因为我们不同数字的二进制位数不同,前导零不应该被计入.
先算出n有的二进制位数符合条件个数,然后再计算二进制位数比n小的即可.
Code
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 34;
LL C[N][N];
int l,r;
void init()
{
for(int i=0;i<N;i++)
for(int j=0;j<=i;j++)
if(!j) C[i][j] =1;
else C[i][j] = C[i-1][j]+C[i-1][j-1];
}
LL dp(int n)
{
if(!n) return 0;
vector<int> v;
int sum[2];
sum[0] = 0,sum[1] = 1;
while(n) v.push_back(n%2),n/=2;
LL res = 0;
for(int i=v.size()-2;i>=0;i--)
{
int x = v[i];
if(x)
{
int cnt = sum[0]+1,maxn;
maxn = i+cnt-sum[1]>>1;
for(int j=0;j<=maxn;j++) res+=C[i][j];
}
sum[x]++;
if(!i&&sum[0]>=sum[1]) res++;
}
for(int i=2;i<v.size();i++)
for(int j=i+1>>1;j<i;j++) res+=C[i-1][j];
return res;
}
int main()
{
init();
while(scanf("%d%d",&l,&r)!=EOF)
printf("%lld\n",dp(r)-dp(l-1));
return 0;
}