Hdu 4734 【数位DP】.cpp

题意:

  我们定义十进制数x的权值为f(x) = a(n)*2^(n-1)+a(n-1)*2(n-2)+...a(2)*2+a(1)*1,a(i)表示十进制数x中第i位的数字。

  题目给出a,b,求出0~b有多少个不大于f(a)的数。

 

思路:

  数位DP,用来学习数位DP了。

  <数位DP>

    所谓数位DP就是基于考虑数字的每一位来转移的DP。

    例如求比456小的数,可以这么考虑,

        4          5               6

          4        5             (0~6)

        4       (0~4)         (0~9)

        (0~3)(0~9)         (0~9)

    然后我们就可以考虑用dp[len][pre]表示长度为len,以pre开头的符合条件的数的个数。

    这样就可以得到转移方程了。

 

  而对于这道题,我们可以用dp[len][pre]表示长度为len且权值不大于pre的数。

  这道题用记忆化搜索,除边界条件外记录dp[len][pre]的值,下一次发现以前已经计算过了就可以直接return;

 

  初值:dp[len][pre] = 0; 

     dfs(len, pre, flag)表示求长度为len,不超过pre的所有符合条件的值。其中flag是用来控制边界的。

     dfs过程中当深搜的边界,发现len < 0,pre >=0 的时候就返回1.

       

Tips:

  下面记忆的时候要记得判断是不是边界,如果是边界算出来的答案是不完整的。

 

Code:

 

 1 /******************************************
 2 *Author:         Griselda
 3 *Created Time:   2013-11-17 18:38
 4 *Filename:       4734.cpp
 5 * ****************************************/
 6 #include <stdio.h>
 7 #include <cstring>
 8 #include <algorithm>
 9 using namespace std;
10 
11 int dp[10][200000], mx[10];
12 int dfs(int len, int pre, bool flag)
13 {
14     if (len < 0) return pre >= 0;
15     if (pre < 0) return 0;
16     if (!flag && dp[len][pre] != -1) return dp[len][pre];
17     int end = flag?mx[len]:9, ans = 0;
18     for (int i = 0; i <= end; ++i) {
19         ans += dfs(len-1, pre-i*(1<<len), flag&&i==end);
20     }
21     if (!flag) dp[len][pre] = ans;
22     return ans;
23 }
24 
25 int f(int x)
26 {
27     int tmp = 1, ans = 0;
28     while (x) {
29         ans += x%10*tmp;
30         x /= 10;
31         tmp *= 2;
32     }
33     return ans;
34 }
35 
36 int cal(int a, int b)
37 {
38     int top = 0;
39     while (b) {
40         mx[top++] = b%10;
41         b /= 10;
42     }
43     return dfs(top-1, f(a), true);
44 }
45 
46 int main()
47 {
48     int iCase = 1, nCase;
49     int a, b;
50     scanf("%d", &nCase);
51     memset(dp, 0xff, sizeof(dp));
52     while (nCase--) {
53         scanf("%d %d", &a, &b);
54         printf("Case #%d: %d\n", iCase++, cal(a, b));
55     }
56     return 0;
57 }
View Code

 

 

 

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4734

转载于:https://www.cnblogs.com/Griselda/p/3433295.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值