2719. 统计整数数目 | 数位dp

44 阅读1分钟

给你两个数字字符串 num1 和 num2 ,以及两个整数 max_sum 和 min_sum 。如果一个整数 x 满足以下条件,我们称它是一个好整数:

  • num1 <= x <= num2
  • min_sum <= digit_sum(x) <= max_sum.

请你返回好整数的数目。答案可能很大,请返回答案对 109 + 7 取余后的结果。

注意,digit_sum(x) 表示 x 各位数字之和。

典型数位dp题目,假设 dfs(x)dfs(x) 表示 00xx 间,满足 minsum<=digitsum(x)<=maxsummin_sum <= digit_sum(x) <= max_sum 的数字个数,那么答案就是 dfs(num2)dfs(num11)dfs(num2) - dfs(num1 - 1)

套用灵神的模板即可。www.bilibili.com/video/BV1rS…

class Solution {
    private static final int MOD = 1000000007;
    public int count(String num1, String num2, int minSum, int maxSum) {
        int ans = calc(num2, minSum, maxSum) - calc(num1, minSum, maxSum) + MOD;
        int sum = 0;
        for(char c : num1.toCharArray()) {
            sum += c - '0';
        }
        if(minSum <= sum && sum <= maxSum) {
            ans++;
        }
        return ans % MOD;
    }

    private int calc(String s, int minSum, int maxSum) {
        int n = s.length();
        int[][] memo = new int[n][Math.min(9 * n, maxSum) + 1];
        char[] ch = s.toCharArray();
        for(int[] row : memo) {
            Arrays.fill(row, -1);
        }
        return dfs(0, 0, true, ch, minSum, maxSum, memo);
    }

    private int dfs(int i, int sum, boolean isLimit, char[] s, int minSum, int maxSum, int[][] memo) {
        if(sum > maxSum) return 0;
        if(i == s.length) return sum >= minSum ? 1 : 0;
        if(!isLimit && memo[i][sum] != -1) return memo[i][sum];
        int res = 0;
        for(int d = 0, up = isLimit ? s[i] - '0' : 9; d <= up; d++) {
            res = (res + dfs(i + 1, sum + d, isLimit && (d == up), s, minSum, maxSum, memo)) % MOD;
        }
        if(!isLimit) memo[i][sum] = res;
        return res;
    }
}