• 数位DP


    题意:(hdu 4734)

      我们定义十进制数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)的数

    #include <stdio.h>
    #include <string.h>
    
    int mx[10];
    int dp[10][200000];
    
    /*
    
      <数位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.
    */
    
    int dfs(int len, int pre, bool flag)
    {
        if ( len < 0 ) return pre >=0;
        if ( pre < 0 ) return 0;
    
        if ( !flag && dp[len][pre] != -1) return  dp[len][pre];
    
        int end = flag?mx[len]:9;
        int ans = 0;
        int i;
        for( i = 0; i <= end; i++)
        {
            ans += dfs(len-1, pre- i*(1<<len), flag&&i==end);
        }
        
        if( !flag )dp[len][pre] = ans;
        return ans;
    }
    
    int f(int x)
    {
        int ans = 0;
        int tmp = 1;
    
        while( x )
        {
           ans += (x%10)*tmp;
           tmp = tmp*2;
           x = x/10;
        }
    
        return ans;
    }
    
    int cal(int a, int b)
    {
        int tmp = 0;
    
        while( b )
        {
           mx[ tmp++ ]= b%10;
           b = b/10;
        }
        return dfs(tmp - 1, f(a),  true );
    }
    
    int main()
    {
        int t;
        int a,b;
        scanf("%d", &t);
        memset(dp, 0xff, sizeof(dp));
        for(int i = 1; i <= t; i++ )
        {
            scanf("%d%d",&a, &b);
            printf("Case #%d: %d
    ", i, cal(a,b));
        }
        return 0;
    }
    当你的才华还撑不起你的野心时,那你就应该静下心来学习。
  • 相关阅读:
    C#socket客户端自己输入消息发送到服务端通信实现通信
    C#设计模式:观察者模式(Observer Pattern)
    C#冒泡排序法学习
    强类型和弱类型
    计算机网络基础知识总结
    推荐几个搜索资源网站
    推荐几个搜索资源网站
    前端:闭包的概念
    前端:闭包的概念
    收集12个经典的程序员段子
  • 原文地址:https://www.cnblogs.com/aceg/p/4467654.html
Copyright © 2020-2023  润新知