题意:
round number的定义是二进制表示中0的个数大于1的数字。
问从a到b范围内的roud number有多少个。
思路:
数位dp,dp[pos][ze][on]表示当枚举到pos位的时候有ze个0和on个1的数字的个数。
这题最重要的就是前导0会对结果产生影响,因为要保证每一个数都是有效的,那么第一位就必须是1,010和10是同一个数字。
所以枚举的时候,如果有前导0,那么对ze和on的贡献就是0.
如果前面已经有了1,那么后面就随意枚举并且当前的0和1都得算入贡献。
代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 const int N = 50; 6 int dp[N][N][N]; 7 int a[N]; 8 int dfs(int pos,int lim,int ze,int on,bool first) 9 { 10 if (pos == -1) 11 { 12 return ze >= on || first; 13 } 14 if (!lim && !first && dp[pos][ze][on] != -1) return dp[pos][ze][on]; 15 int res = 0; 16 int mx = lim ? a[pos] : 1; 17 for (int i = 0;i <= mx;i++) 18 { 19 if (first) 20 { 21 if (i == 0) res += dfs(pos-1,i == mx && lim,0,0,first); 22 else res += dfs(pos-1,i == mx && lim,0,1,0); 23 } 24 else 25 { 26 res += dfs(pos-1,i == mx && lim,ze + !i,on + i,first); 27 } 28 } 29 if (!lim && !first) dp[pos][ze][on] = res; 30 return res; 31 } 32 int solve(int x) 33 { 34 int pos = 0; 35 while (x) 36 { 37 a[pos++] = x % 2; 38 x /= 2; 39 } 40 int res = dfs(pos-1,1,0,0,1); 41 return res; 42 } 43 int main() 44 { 45 int s,f; 46 memset(dp,-1,sizeof(dp)); 47 while (scanf("%d%d",&s,&f) != EOF) 48 { 49 int ans = solve(f) - solve(s-1); 50 //printf("%d ",solve(f)); 51 printf("%d ",ans); 52 } 53 return 0; 54 }