题意:
如果你个数的二进制中1的个数要小于等于0的个数,那么这个数就符合题意。现在要你找出来区间[li,ri]这个区间内有多少这样的数
题解:
题意很明显了,是要用二进制,所以我们也把给的区间边界转化成二进制存在数组里面。然后再来枚举。要注意一点前导零可不能算在进去。比如1,它的二进制是1,那么也可以是01、001、0001等。所以前导零要排除。
dp[x][y][z]表示从开始到x位,没有前导零的前提下,已经有y个0,z个1。注意要没有前导零
在dfs过程中如果一个数前导零还存在情况下是不能直接返回dp值的,同样枚举到这个位置前导零还存在的话也不能赋值给dp数组比如二进制0001和1000他们在dp数组中所占的位置是一样的。这样就会错!
代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<iostream> 5 using namespace std; 6 const int maxn=105; 7 typedef long long ll; 8 ll v[maxn],dp[maxn][maxn][maxn],ci,w[maxn]; 9 ll dfs(int pos, int one, int zero, bool flag, bool limit) 10 { 11 if (pos == -1) 12 { 13 if (one <= zero) return 1; 14 return 0; 15 } 16 if (!limit && flag && dp[pos][one][zero] != -1) return dp[pos][one][zero]; 17 int up = limit ? v[pos] : 1; 18 ll res = 0; 19 for (int i = 0; i <= up; i++) 20 { 21 if (i == 0) 22 { 23 if (flag) res += dfs(pos - 1, one, zero + 1, flag, limit && v[pos] == i); 24 else res += dfs(pos - 1, one, zero, flag, limit && v[pos] == i); 25 } 26 else res += dfs(pos - 1, one + 1, zero, true, limit && v[pos] == i); 27 } 28 if (!limit && flag) dp[pos][one][zero] = res; 29 return res; 30 } 31 ll solve(ll ans) 32 { 33 ll pos=0; 34 while(ans) 35 { 36 v[pos++]=ans%2; 37 ans/=2; 38 } 39 ci=pos; 40 return dfs(pos-1,0,0,false,true); 41 } 42 int main() 43 { 44 45 ll l,r; 46 memset(dp,-1,sizeof(dp)); 47 scanf("%I64d%I64d",&l,&r); 48 printf("%I64d ",solve(r)-solve(l-1)); 49 return 0; 50 }