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

你可能感兴趣的:(HDU)