zoukankan      html  css  js  c++  java
  • 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
    ", iCase++, cal(a, b));
    55     }
    56     return 0;
    57 }
    View Code

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

  • 相关阅读:
    mysql相关
    java注解@Valid@Validated表单验证
    驼峰参数、下划线["_"]参数,属性互传
    redis,windows设置记录
    Java入门第一季学习总结
    计算属性calc()的运算规则
    swiper实现翻页,页面高度超出可滚动
    git常用命令
    Linux下svn常用命令
    图片高度不够一页,如何覆盖全屏
  • 原文地址:https://www.cnblogs.com/Griselda/p/3433295.html
Copyright © 2011-2022 走看看