zoukankan      html  css  js  c++  java
  • hdu 4722 Good Numbers 数位dp

    Good Numbers

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 602    Accepted Submission(s): 220


    Problem Description
    If we sum up every digit of a number and the result can be exactly divided by 10, we say this number is a good number.
    You are required to count the number of good numbers in the range from A to B, inclusive.
     

    Input
    The first line has a number T (T <= 10000) , indicating the number of test cases.
    Each test case comes with a single line with two numbers A and B (0 <= A <= B <= 1018).
     

    Output
    For test case X, output "Case #X: " first, then output the number of good numbers in a single line.
     

    Sample Input
    2 1 10 1 20
     

    Sample Output
    Case #1: 0 Case #2: 1
    Hint
    The answer maybe very large, we recommend you to use long long instead of int.
     

    ---------------------

    求区间[l,r]之间有多少个数,各位数和能被10整除。

    转化为get(x),区间[0,x]之间有多少个数满足条件。

    则答案即为get(r)-get(l-1),问题转化为数位dp。

    将x的各位数字储存在bit[]中。

    考虑区间[0~5132]

    可以转化成[0~999] 、[1000~1999]、[2000~2999]、[3000~3999]、[4000~4999]、[5000~5099]、[5100~5109]、[5110~5119]、[5120~5129]、[5130~5132]

    令f[i][j]表示前i位和模10得j的方案数。若i为最后一位,若j=0则f[i][j]=1,否则f[i][j]=0。

    用记忆化搜索实现数位dp

    dp(int p,int m,bool flag),flag=true 表示当前位p无论取多少都小于数x 。

    则dp(i,m) += dp(i+1,(m+k)%10) 0=<k<= (9 or bit[i])

    -------------------------

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    
    using namespace std;
    typedef long long LL;
    const int maxn=111;
    LL f[maxn][11];
    int bit[maxn];
    int n;
    LL dp(int p,int m,bool flag){
        if (p==0) return (m==0);
        if (flag&&f[p][m]!=-1) return f[p][m];
        int k=flag?9:bit[p];
        LL res=0;
        for (int i=0;i<=k;i++){
            res+=dp(p-1,(m+i)%10,flag||k!=i);
        }
        if (flag) f[p][m]=res;
        return res;
    }
    
    LL get(LL x){
        memset(f,-1,sizeof(f));
        if (x<0) return 0;
        n=0;
        while (x!=0){
            bit[++n]=x%10;
            x/=10;
        }
        return dp(n,0,0);
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        for (int cas=1;cas<=T;cas++){
            LL x,y;
            scanf("%I64d%I64d",&x,&y);
            printf("Case #%d: %I64d
    ",cas,get(y)-get(x-1));
        }
        return 0;
    }
    




  • 相关阅读:
    vc++ 最小化到托盘的详细实现
    WS_CLIPCHILDREN和WS_CLIPSIBLINGS的理解(转载)
    windows 进程间通讯方法
    C++中各种数据量类型转换
    WTL 自绘 进度条Progressbar
    C++ 读取XML文件(tinyXML库的应用)
    WTL 自定义 Button类-自绘
    设计模式课程 设计模式精讲 27-3 状态模式源码解析
    设计模式课程 设计模式精讲 27-2 状态模式coding
    设计模式课程 设计模式精讲 26-3 访问者模式源码解析
  • 原文地址:https://www.cnblogs.com/cyendra/p/3681580.html
Copyright © 2011-2022 走看看