题意:
找出给定范围中满足这个条件的数的个数:这个数各个转化成2进制0个数大于1的个数。
题解:
设定状态:因为这题各个数位的关系只与0、1的个数有关,那么就可以这样dp[pos][one][zero]位数pos一的个数为one零的个数为zero满足条件数的个数。
注意前导零的问题,所以在搜索时加了特别的判断!因为二进制只有0和1,前导零是不算在这个数中零的个数上面的。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<math.h>
using namespace std;
typedef __int64 lld;
#define oo 0x3f3f3f3f
#define digit 66
#define maxn 82
lld dp[digit][digit][digit];
int bit[digit];
lld dfs(int pos,int one,int zero,int pre0,int f)
{
if(pos<1) return zero>=one;
if(!f&&dp[pos][one][zero]!=-1) return dp[pos][one][zero];
int last=f?bit[pos]:1;
lld res=0;
for(int i=0;i<=last;i++)
{
//pre0=0表示有前导零,pre0=1表示没有
if(pre0==0)
{
if(i==0)
res+=dfs(pos-1,0,0,0,f&&i==last);
else
res+=dfs(pos-1,1,0,1,f&&i==last);
}
else
{
if(i==0)
res+=dfs(pos-1,one,zero+1,pre0,f&&i==last);
else
res+=dfs(pos-1,one+1,zero,pre0,f&&i==last);
}
}
if(!f) dp[pos][one][zero]=res;
return res;
}
lld Cnt(lld n)
{
int len=0;
while(n)
{
bit[++len]=n%2;
n/=2;
}
return dfs(len,0,0,0,1);
}
int main()
{
int T;
lld a,b;
memset(dp,-1,sizeof dp);
while(scanf("%I64d %I64d",&a,&b)!=EOF)
{
printf("%I64d\n",Cnt(b)-Cnt(a-1));
}
return 0;
}