题目链接
题目大意:
将数字转化为二进制,统计 二进制数中0的个数不下于1 的数字的个数;
分析:
(1)试想一下,在pos位置,pos之后的0和1的数目是一定的,如果dfs时,有多条路径,到pos之前的0和1的数目相同,
那么只要第一次到达pos时,更新并记录了信息,此后再到达pos点就可以使用这个信息了。而这个找到这三个信息,
需要:位置,此时1的数目,0的数目;所以dp数组,写成:dp[pos][num0][num1]
(2)确定了dp数组如何写,还要确定dfs方程的写法:(***dp数组的因素+限制条件***)
dfs(int pos,bool lead,bool limit)基本的内容;
需要num0,num1的数目,dfs(int pos,int num,int num1,bool lead,bool limit)
(3)pos==-1的时候如何处理:return num0 >=num1;
(4)for循环内部如何处理:(这里需要处理前导0)
for(int i=0;i<=up;i++)
{
if(lead)
sum+=dfs(pos-1,num0,num1+(i==1),lead&&i==0,limit&&i==up);
else
sum+=dfs(pos-1,num0+(i==0),num1+(i==1),lead&&i==0,limit&&i==up);
}
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
int dp[65][30][30];
int a[65];
int dfs(int pos,int num0,int num1,bool lead,bool limit)
{
if(pos==-1&&num0>=num1) return 1;
if(pos==-1) return 0;
if(!limit&&!lead&&dp[pos][num0][num1]!=-1) return dp[pos][num0][num1];
int up=limit?a[pos]:1;
int sum=0;
for(int i=0;i<=up;i++)
{
if(lead)
sum+=dfs(pos-1,num0,num1+(i==1),lead&&i==0,limit&&i==up);
else
sum+=dfs(pos-1,num0+(i==0),num1+(i==1),lead&&i==0,limit&&i==up);
}
if(!limit) dp[pos][num0][num1]=sum;
return sum;
}
int solve(int k)
{
int pos=0;
while(k)
{
a[pos++]=k&1;
k>>=1;
}
int ans=dfs(pos-1,0,0,1,1);
return ans;
}
int main()
{
int a,b;
memset(dp,-1,sizeof(dp));
scanf("%d%d",&a,&b);
int x=solve(a-1);
int y=solve(b);
printf("%d",y-x);
return 0;
}