zoukankan      html  css  js  c++  java
  • HDU 4734 数位DP

    http://www.cnblogs.com/Griselda/archive/2013/11/20/3433295.html

    上面那个链接讲得挺清楚,简单贴一下:

    数位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.

    这里主要想讲一下为什么想到用数位DP,或者说数位DP可以解决什么问题

    题目是给出一个限定值,求这个限定值下满足条件的个数。而这个值求得的过程是每个位分别运算得出来的,所以我们很自然可以每个位分别去算,一直算到最后一个位得出结果。

    dp[len][pre]表示长度为len且权值不大于pre的数

    #include <iostream>
    #include <string>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <vector>
    #include <iterator>
    #include <set>
    #include <map>
    #include <sstream>
    using namespace std;
    
    #define mem(a,b) memset(a,b,sizeof(a))
    #define pf printf
    #define sf scanf
    #define spf sprintf
    #define pb push_back
    #define debug printf("!
    ")
    #define MAXN 1000000000 +5
    #define MAX(a,b) a>b?a:b
    #define blank pf("
    ")
    #define LL long long
    #define ALL(x) x.begin(),x.end()
    #define INS(x) inserter(x,x.begin())
    #define pqueue priority_queue
    #define INF 0x3f3f3f3f
    
    #define ls (rt<<1)
    #define rs (rt<<1|1)
    
    int n,m;
    
    int a[20];
    
    int dp[20][200000];
    
    int dfs(int pos,int pre,bool flag)
    {
        if(pre<0) return 0;
        if(pos<0) return pre>=0;
        if(!flag && dp[pos][pre] != -1) return dp[pos][pre];
        int e = flag?a[pos]:9;
        int ans  = 0;
        for(int i = 0;i<=e;i++)
        {
            ans += dfs(pos-1,pre-i*(1<<pos),flag && i==e);
        }
        if(!flag) dp[pos][pre] = ans;
        return ans;
    }
    
    int main()
    {
        int t,kase=1,i,j,k;
        sf("%d",&t);
        mem(dp,-1);
        while(t--)
        {
            sf("%d%d",&n,&m);
            int len = 0,pre = 0,tmp=1;
            while(m)
            {
                a[len++] = m%10;
                m/=10;
            }
            while(n)
            {
                pre+= tmp * (n%10);
                tmp*=2;
                n/=10;
            }
            /*
            for(i=0;i<len;i++) pf("%d
    ",a[i]);
            pf("%d %d
    ",len,pre);
            */
            pf("Case #%d: %d
    ",kase++,dfs(len-1,pre,true));
        }
        return 0;
    
    }
  • 相关阅读:
    MySQL update && select ,update的同时select,和for update 语句说再见。
    宋体文件C#读取CSV文件java教程
    输入格式邮箱验证格式
    状态集合[Python]Socket高级 select I/O复用模型(二)
    运行下载运行google play闪退的解决办法java教程
    Hibernate查询
    Hibernare 的基本介绍
    Hibernate详细配置
    人工智能能力提升指导总结
    如何根据普通ip地址获取当前地理位置
  • 原文地址:https://www.cnblogs.com/qlky/p/5743174.html
Copyright © 2011-2022 走看看