数位统计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';
}

浙公网安备 33010602011771号