数位DP统计->数字计数(洛谷2602)
题意:统计区间内每个数字出现的次数
分析:前缀和差分,数位dp,从高到低考虑,有一种特殊情况是统计0出现的次数时,要考虑前导0
void solve(){
long long l, r;
cin >> l >> r;
vector<int> num;
int digit;
vector<vector<long long>> dp(14, vector<long long>(14, -1));
function<long long int(int, long long, bool, bool)> dfs = [&](int pos, long long sum, bool lead, bool limit) -> long long{
if (pos == 0){
return sum;
}
if (lead == false && 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){
if (lead == true && i == 0){
res += dfs(pos - 1, sum, true, limit && i == up); //当前pos考虑的数是0,而且前面所有已经考虑了的数都是0
}
else{
res += dfs(pos - 1, sum + (i == digit), false, limit && (i == up)); //假设i=0,lead=false,说明当前的0不是前导0,可以进行计数了
}
}
if (limit == false && lead == false){
dp[pos][sum] = res;
}
return res;
};
auto cal = [&](long long x, int i)->long long{
for (auto & x : dp){
fill(x.begin(), x.end(), -1);
}
num.resize(1);
while (x){
num.emplace_back(x % 10);
x /= 10;
}
return dfs(int(num.size()) - 1, 0, true, true);
};
for (int i = 0; i < 10; ++i){
digit = i;
cout << cal(r, i) - cal(l - 1, i) << ' ';
}
}

浙公网安备 33010602011771号