poj 3252 Round Numbers

题意:

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\n",solve(f));
51         printf("%d\n",ans);
52     }
53     return 0;
54 }

猜你喜欢

转载自www.cnblogs.com/kickit/p/9034803.html
今日推荐