【acwing】数位dp的思路

本文探讨了数位动态规划(DP)的概念,强调其在解决区间内满足特定条件的数字个数问题上的应用。核心思想是维护一个DP数组,通过前缀和和树状结构分析来转移状态。文中通过三个例题详细解释了数位DP的解题思路,包括不降数字计数、计算度和复杂计数问题的解决方案。
摘要由CSDN通过智能技术生成

偷师acwing,学习数位DP的策略。

引言

数位dp的特点,求解在一个区间内满足某特性的数字的个数。数位dp具有两个特点,第一个,利用前缀和的特点求解区间[left, right]的问题,分别求出【0,left-1】和【0,right】的个数。第二个特点是树,对每一位依次进行分析。

核心的思想,首先我们需要维护一个dp数组,这个数组一般由这么几个状态组成:
剩余的位数i,前一位的数组的填充j,求解满足调节的必要信息k

具体的dp转移思路时,是与题目要求的条件有关。如要求出现几个1,全部数字不降,前后数字之差等。

在完成计算dp之后,需要开始求解在区间中满足条件的数字。首先把判断0的情况,然后数字拆分为每一位。计算每一位的情况时分为两种情况,比如这一位是an,情况一是可以完整的取0~an-1的全部情况,另外一种是这一位取an,因为是无法完成取到全部的值的,注意这个情况要每次判断是否合法,不合法就break。

如果有幸能到最后一位数字,最后加一,表示最后一种情况。

例题 不降数字

给定区间[l, r]求区间内所有是整数,满足低位不小于高位的数值的个数。如,1234,2333.

首先我们定义一个dp[i][j]表示在还有i位的情况下,最高位位j的情况下满足的个数。

显然我们可以知道dp[i][j] += dp[i-1][k] 其中j<=k<10.

然后我们分析问题,关键的信息有lastres,存储了上一位的信息,和当前的个数
第一步:把num拆分开成每一位的形式。从最高位开始,寻找可能的解。
第二步:结合树形图,依次求解。


class Solution():
    def test(self, l, r):
        # l表示左端点 0<=l<r:
        # dp[i][j]表示存在i位,最大数字是j,满足非降的个数
        # 设置为15保证了最长可以有15位的整数
        dp = [[0]*10 for _ in range(15)]
        for j in range(10):
            dp[1][j] = 1
        for i in range(2,15):
            for j in range(10):
                for k in range(j, 10):
                    dp[i][j] += dp[i-1][k] 
        #print(dp)
        def helper(n):
            res = 0
            last = 0
            num = []
            # 首先判断0
            if not n:
                return 1
            # 拆分数字
            while n:
                num.append(n%10)
                n //= 10
            for i in range(len(num)-1, -1, -1):
                x = num[i]
                # 判断有没有必要枚举
                if last>x:
                    break  
          # 这种情况下没必要在枚举了,已经全部枚举了如12854,枚举完12700d的全部,剩下的不可能满足了
          		# 计算所有左侧的情况
                for j in range(last, x):
                    res += dp[i+1][j]
                # 右侧的情况
                last = x
                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值