给你一个区间,求区间内的round number的个数,如果一个数字的二进制表示中,0的个数大于等于1的个数,则这个数字叫做round number。 把数字用二进制表示出来,然后数位dp一发就好。这个题前导0会影响到结果,所以要考虑前导0。我做的时候就没想前导0,看了题解才想到还有前导0呢。 参考:http://blog.csdn.net/wust_zzwh/article/details/52100392 dp[pos][num]是dp的数组,pos表示枚举到第pos位,num表示0的个数和1的个数的差。因为差可能会小于0,所以要加上个数,让他大于0。
#include <stdio.h> #include <string.h> const int der = 32; int dp[36][66]; int digit[36]; int len; void calc(int num) { len = 0; while(num) { digit[len++] = num&1; num >>= 1; } } //s表示0的数量减掉1的数量 //多了一个lead表示有无前导0 //在这里前导0对数字有影响 int dfs(int i, int s, bool lead,bool e) { if(i == -1) return s>=der; if(!e && !lead && ~dp[i][s]) return dp[i][s]; int res = 0; int u = e?digit[i]:1; for(int d = 0; d <= u; ++d) { //如果存在前导0,则不计数 if(lead && d == 0) res += dfs(i-1, s, lead, e&&d==u); else res += dfs(i-1, s+(d==0?1:-1), lead&&d==0, e&&d==u); } if(!e && !lead) dp[i][s] = res; return res; } int solve(int num) { calc(num); return dfs(len-1,der,true,true); } int main() { memset(dp,-1,sizeof(dp)); int s,e; scanf("%d %d",&s,&e); printf("%d\n",solve(e)-solve(s-1)); return 0; }