题意:给定一个区间[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 <cstdio> #include <cstring> #include <vector> #include <string> 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; }