• HDU 2089 不要62 (数位DP)


    第一次做数位dp的题,虽然是入门题,真的是想了好久才想明白。

    dp[i][j] 表示i位数,首位是j的数字有多少符合要求的。

    很容易得到递推公式 :

    如j=4时:dp[i][j]=0

    j!=4时:

    递推公式

    如何根据数组dp求对于一个数n,0~n满足要求的数呢?

    对于一个数,例如335,对应dp[3][3],但是满足要求的数有336,347,358……这些数超过了335……

    所以通过dp[3][0],dp[3][1],dp[3][2]求得首位数字小于3的满足条件的三位数,dp[3][0]求得的数是001,052,093...也就是所有满足条件的一位或两位数……我们求得所有的2xx,1xx,0xx.

    接下来要求的是如334,327这类首位是3满足条件的数字,既然首位只能是3,也就是第一位已经选完了,那么我们只要选择满足小于35的数字就可以了。和上面同理,我们只要求出dp[2][0],dp[2][1],dp[2][2],dp[2][3],dp[2][4]就可以求出首位小于3的两位数。这时求得的是32x,31x,30x。

    然后我们求所有小于5的数字就ok。小于5也就是dp[0],dp[1],dp[2],dp[3],dp[4]。这时求得的是53x.

    到此,所有小于335且满足的数全部求出。

    但是还需要考虑的问题是62,4。

    如果某一位数字为4,如77432的第三位(从左向右看)是4,那么我们依次求出6xxxx,5xxxx,...,0xxxx,76xxx,75xxx,...,70xxx,773xx,773xx,...,770xx,我们接来下需要求的是7742x....7740x,但这时所求的数是774xx的数,必然含有4,所以这时我们停止。

    对于62,如果某一位数字是6,如5675,我们求完5xxx,4xxx,...0xxx之后再求56xx时,注意566x,565x,..,563x,561x,没有562x。如果数字中含有62,如5627,那么同4,求到562x的时候就应该停止继续求下去了。

    因为求得的是小于n的数,所以求[0,n]之间的数需要求n+1.

    代码:

    /*******************************************
    Problem : 2089 ( 不要62 )     Judge Status : Accepted
    RunId : 14481604    Language : G++    Author : G_lory
    Code Render Status : Rendered By HDOJ G++ Code Render Version 0.01 Beta
    *******************************************/
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    int dp[10][10];
    int d[10];
    
    void init()
    {
        dp[0][0] = 1;
        for (int i = 1; i <= 7; ++i)
            for (int j = 0; j <= 9; ++j)
                for (int k = 0; k <= 9; ++k)
                    if (j != 4 && !(j == 6 && k == 2))
                        dp[i][j] += dp[i - 1][k];
    }
    
    int solve(int n)
    {
        int ans = 0;
        int len = 0;
        while (n) {
            ++len;
            d[len] = n % 10;
            n /= 10;
        }
        d[len + 1] = 0;
        for (int i = len; i >= 1; --i) {
            for (int j = 0; j < d[i]; ++j) {
                if (d[i + 1] != 6 || j != 2)
                    ans += dp[i][j];
            }
            if (d[i] == 4 || (d[i + 1] == 6 && d[i] == 2))
                break;
        }
        return ans;
    }
    
    int main()
    {
        int m, n;
        init();
        while (scanf("%d%d", &m, &n) == 2) {
            if (n == 0 && m == 0) break;
            printf("%d
    ", solve(n + 1) - solve(m));
        }
        return 0;
    }
    

      

  • 相关阅读:
    基于Enterprise Library 6 的AOP实现
    命行下的查询与替换字符串
    软件架构中质量特性
    【redis】突然流量增大,不定时挂死排障记录
    Heritrix 3.1.0 源码解析(二)
    Apache Jackrabbit源码研究(四)
    Heritrix 3.1.0 源码解析(三)
    Apache Jackrabbit源码研究(五)
    Heritrix 3.1.0 源码解析(一)
    JVM 自定义的类加载器的实现和使用
  • 原文地址:https://www.cnblogs.com/wenruo/p/4725005.html
Copyright © 2020-2023  润新知