数位统计dp->烦人的数学作业(洛谷4999)

https://www.luogu.com.cn/problem/P4999

题意:给定区间[l, r],求[l,r]内所有数字的每位dight相加的总和。

分析:数位dp,前缀和差分,从最高位往最低位考虑。

//更好的理解dp[pos][sum], 当考虑pos位的时候,pos位肯定有一个sum值,而这个sum值继续往下搜,可能已经搜过了,就造成了重复搜索。
//dp[pos][sum]表示当最高位到pos位的和为sum时,从pos - 1位到第1位的所有的可能的合法的组合对答案的贡献值
void solve(){
    long long l, r;
    cin >> l >> r;

    vector<vector<long long>> dp(20, vector<long long>(180, -1));
    vector<int> num;
    function<long long(int, int, bool)> dfs = [&](int pos, int sum, bool limit) ->long long{
        if (pos == 0){
            return sum;
        }
        if (limit == false && dp[pos][sum] != -1){
            return dp[pos][sum];
        }

        int up = (limit == true ? num[pos] : 9);
        long long res = 0;
        for (int i = 0; i <= up; ++i){
            res = (res + dfs(pos - 1, sum + i, limit && i == up)) % mod;        //如果limit是false那就永远是9,不然当i到了当前最高限制位的时候,下一位就要被限制
        }
        if (limit == false){
            dp[pos][sum] = res;
        }
        return res;
    };

    auto cal = [&](long long x)->long long{
        num.resize(1);
        for (long long t = x; t; t /= 10){
            num.emplace_back(t % 10);
        }
        return dfs(int(num.size()) - 1, 0, true);       //最高位肯定有限制,所以是true。
    };


    cout << (cal(r) - cal(l - 1) + mod) % mod << '\n';
}
posted @ 2024-01-15 10:19  _Yxc  阅读(20)  评论(0)    收藏  举报