题意:给定一个区间[n,m],求这个区间内的round数的数量。所谓round数,就是这个数的二进制表示(不含前导零)中0出现的个数不比1出现的个数少。前几个Round数:0,2,4,8,9,10,12。
思路:dp。dfs(int k,int hasone,int numone,int limit)这几个参数的意思是:
k:当前处理的是第几位
hasone:之前是否出现过1
numone:之前出现的数字1的数量,可以为负数,所以off函数就是将这个数映射到整数区间。
limit:是否有上界。
其中dp数组的第三维分为是否之前出现过1,这个不要忘记。比如dfs(2,0,0,0)和dfs(2,1,0,0)这两个返回值应该是不一样的。前者之前没有出现过1,所以不能有前导零,合理的只有0和10.而后者合理的有三个:0,01,10
#include
#include
#include
#include
using namespace std;
int n,m;
int d[35],len;
int dp[32][64][2];
int off(int x){
return x+32;
}
int dfs(int k,int hasone,int numone,int limit){
if(k==0)
return numone<=0;
if(!limit && dp[k][off(numone)][hasone]!=-1)
return dp[k][off(numone)][hasone];
int res = 0;
if(limit){
if(d[k]==0)
res += dfs(k-1,hasone,numone-hasone,1);
else
res += dfs(k-1,hasone, numone-hasone, 0) + dfs(k-1,1,numone+1,1);
}else
res += dfs(k-1, hasone, numone-hasone, 0) + dfs(k-1, 1, numone+1, 0);
if(limit == 0)
dp[k][off(numone)][hasone] = res;
return res;
}
int solve(int x){
len = 0;
while(x){
d[++len] = x&1;
x>>=1;
}
return dfs(len,0,0,1);
}
int main(){
memset(dp,-1,sizeof(dp));
while(scanf("%d %d",&n,&m) != EOF)
printf("%d\n",solve(m)-solve(n-1));
return 0;
}