题意:算给定区间中,数的二进制种0的数量不少于1的数量的数字有多少个
思路:这题的约束就是一个数的二进制中0的数量要不能少于1的数量,dp[pos][num],到当前数位pos,0的数量减去1的数量为num的方案数,一个简单的问题,中间某个pos位上num可能为负数(这不一定是非法的,因为我还没枚举完嘛,只要最终的num>=0才能判合法,中途某个pos就不一定了),这里比较好处理,Hash嘛,最小就-32吧(好像),直接加上32,把32当0用。这题主要是要想讲一下lead的用法,显然我要统计0的数量,前导零是有影响的。只有!lead&&!limit才能dp
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
int dp[35][66];
int a[66];
int dfs(int pos,int sta,bool lead,bool limit)
{
if(pos==-1)
return sta>=32;
if(!limit&&!lead&&dp[pos][sta]!=-1) return dp[pos][sta];//处理先导0
int up=limit?a[pos]:1;
int ans=0;
for(int i=0;i<=up;i++)
{
if(lead&&i==0) ans+=dfs(pos-1,sta,lead,limit&&i==a[pos]);//有前导零就不统计在内
else ans+=dfs(pos-1,sta+(i==0?1:-1),lead&&i==0,limit&&i==a[pos]);
}
if(!limit&&!lead ) dp[pos][sta]=ans;
return ans;
}
int solve(int x)
{
int pos=0;
while(x)
{
a[pos++]=x&1;
x>>=1;
}
return dfs(pos-1,32,true,true);
}
int main()
{
memset(dp,-1,sizeof(dp));
int a,b;
while(scanf("%d%d",&a,&b)==2)
{
printf("%d\n",solve(b)-solve(a-1));
}
return 0;
}