zoukankan      html  css  js  c++  java
  • Lightoj 1140(数位DP)

    求一个区间内的数含有多少个0.

    dp[len][pre]表示长度为len的数,含有pre个0.

    需要加一个标记,来表示前缀是否为0(可以是一串连续的0),如果前缀一直为0,就一直搜,如果前缀不为0,就可以用到dp[len-1][pre+1]或者dp[len-1][pre]

    了,如果前缀的最后一位是0,就是dp[len-1][pre+1],如果前缀的最后一位不是0,就是dp[len-1][pre],当然了第一次肯定是需要先搜的.

    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    #define LL long long
    #define maxn 30
    LL   dp[maxn][maxn];//代表长度为len的数字,有多少个0
    LL  digit[maxn];
    int LEN;
    LL dfs(int len,LL pre,int  flag,bool fp) //dfs版本的纯属暴力枚举每一个数字,而递推版本的是考虑了前缀的影响
    {
        if(len==0)
        {
              if(flag)
                 return   1;
              else
                 return  pre;
        }
        if(!fp && dp[len][pre] != -1 && !flag) //如果之前的数字不全是0,可以直接用
        {
             return dp[len][pre];
        }
        LL    ret =0;
        int   fpmax = fp ? digit[len] : 9;
        for(int i=0;i<=fpmax;i++) //分别算出以i开头的数的方案数,
        {
                LL temp=0;
                if(flag) //如果之前一直是0
                {
                     temp=dfs(len-1,pre,flag && (i==0),fp && i==fpmax);
                     ret+=temp;
                }
                else
                {
                     if(i==0)
                     {
                         temp=dfs(len-1,pre+1,flag,fp && i==fpmax);
                         ret+=temp;
                     }
                     else
                     {
                         temp=dfs(len-1,pre,flag,fp && i==fpmax);
                         ret+=temp;
                     }
                }
        }
        if(!fp && !flag) //如果之前的数字不全是0
           dp[len][pre]= ret;
        return  ret;
    }
    
    LL f(LL n)
    {
        if(n==-1)
            return 0;
        int len=0;
        while(n)
        {
            digit[++len] = n % 10;
            n /= 10;
        }
         LL ans=0;
        // LEN=len;
         ans+=dfs(len,0,1,true);
         return ans;
    }
    void init()
    {
        memset(dp,-1,sizeof(dp));
    }
    int main()
    {
       //freopen("test.txt","r",stdin);
        int t;
        scanf("%d",&t);
        int Case=0;
        while(t--)
        {
            init();
            LL n,m;
            scanf("%lld%lld",&n,&m);
             LL ans1=f(m);
            // printf("%lld
    ",ans1);
              init();
             LL ans2=f(n-1);
           //  printf("%lld
    ",ans2);
           printf("Case %d: %lld
    ",++Case,ans1-ans2);
        }
        return 0;
    }
  • 相关阅读:
    [LeetCode] 17. 电话号码的字母组合 ☆☆☆(回溯) ###
    [LeetCode] 22. 括号生成 ☆☆☆(回溯)
    [LeetCode] 15. 3Sum ☆☆☆(3数和为0)
    Trie 树(字典树)
    dubbo框架梳理
    Linux内存管理与C存储空间
    C语言实现的minixml解析库入门教程
    函数不定参数个数的实现
    C语言变量名转字符串的方法
    C语言编译和链接
  • 原文地址:https://www.cnblogs.com/xianbin7/p/4750440.html
Copyright © 2011-2022 走看看