zoukankan      html  css  js  c++  java
  • #2089: 不要62 (数位dp模板题,附带详细解释)

    题目链接
    题意:问区间[n,m]中,不含数字4,也不含数字串“62”的所有数的个数。

    思路:可以转化成求区间[0,x]

    第一次接触数位dp,参考了这几篇博客。

    不要62(数位dp)解题报告

    解题报告2

    解题报告3

    比较重要的前提:

    **¨对于一个小于n的数,肯定是从高位到低位出现某一位

    ¨如 n = 58 n为十进制数。

    **¨ x = 49 此时x的十位

    **¨ x = 51 此时x的个位

    **¨有了上述性质,我们就可以从高到低枚举第一次

    这样之前的位确定了,之后的位就不受n的限制即从00…0~99…9,可以先预处理

    以及写成递归形式代码会简洁很多,所以就写了递归形式。

    更详细的解释参加代码注释。

    #include<bits/stdc++.h>
    #define fst first
    #define sec second
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define ms(a,x) memset(a,x,sizeof(a))
    typedef long long LL;
    #define pi pair < int ,int >
    #define MP make_pair
    using namespace std;
    const double eps = 1e-8;
    const int dx[4] = { 1,0,0,-1 };
    const int dy[4] = { 0,1,-1,0 };
    const int inf = 0x3f3f3f3f;//1061109567
    int n, m;
    int dp[30][2];
    int digit[30];
    
    int dfs(int pos, bool preis6, bool limit) {//pos表示从低到高的第几位,是从高位往低位递归的(也就是从左到又)
                                              // preis6 表示上一个数字是否为6,
                                              // limit表示该位置是否有限制。
        //cout<<pos<<" "<<preis6<<" "<<limit<<" "<<endl;
        if (!pos)return 1;//到该位置表明找到了一个解.
        int res = 0;
        //如果不是limit位置,表示结果是通用的,而之前又算过的话,就可以直接调用这个结果。
        if (!limit && dp[pos][preis6] != -1)return dp[pos][preis6];
        //mx第pos位置能取到的最大的数字..如果不是limit,则可以0..9任意取。
        int mx = limit ? digit[pos] : 9;
        //cout<<"mx:"<<mx<<endl;
    
        for (int i = 0; i <= mx; i++)
        {
            if (i == 4 || (i == 2 && preis6)) continue;
            res += dfs(pos - 1, i == 6, limit&&i == mx);
            //(limit&&i==mx)中limit的含义是。。如果当前一位不是limit位(即0..9可以随便取的位置)
            //,那么之后的位置也一定不是limit位置。
            //而i==mx部分的意思是,在当前位置的数字小于当前位置的数字能取的最大值(mx)之前,
            //后面位的数字随便取也不会超过上界。
        }
    
        if (!limit) dp[pos][preis6] = res;  //记忆化. 非limit位的结果才通用,不然没必要存。
    
        return res;
    
    }
    int solve(int n) {
        ms(digit, 0);
        int len = 0;
        //将数按照每一位存到digit数组中
        while(n) {
            digit[++len] = n % 10;
            n /= 10;
        }
        return dfs(len, false, true);
    }
    int main() {
        ios::sync_with_stdio(false);
        while (cin >> n >> m && n&& m) {
            ms(dp, -1);
            int ans = solve(m) - solve(n - 1);
            cout << ans << endl;
        }
    
        return 0;
    }
    
  • 相关阅读:
    DokuWiki 插件使用
    DokuWiki 命名空间管理
    Ubuntu 14.10 下DokuWiki安装
    Ubuntu 14.10 下安装Ambari
    Ubuntu 14.10 下安装Ambari 问题汇总
    Hadoop 权限管理
    Spark 性能调优-内存设置-GC设置
    Ubuntu 14.10 下NodeJS Cannot find module 'npmlog'
    Hadoop 新增删除节点
    Ubuntu 14.10 下开机不进入图形化界面
  • 原文地址:https://www.cnblogs.com/RioTian/p/12808375.html
Copyright © 2011-2022 走看看