Count One Digit from Zero to n
National Olympiad — Regional round (2015 season)
Submission name: digits.cpp
Problem summary
Count every occurrence of decimal digit k in the ordinary representations of all integers from 0 through n, including both endpoints and the single representation 0.
Input
k n.
Output
The total number of occurrences.
Constraints
0 ≤ k ≤ 9; 0 < n ≤ 10^18.
Worked example
Input and output for the worked example discussed below.
Input
3 42
Output
14
Solution analysis
- Count one decimal position at a time: units, tens, hundreds, and so on. For place value f, split n into higher=n/(10f), current=(n/f) mod 10, and lower=n mod f. Each complete cycle contributes higher×f copies of a nonzero target digit.
- For nonzero k, the incomplete final cycle contributes f if current>k, lower+1 if current=k, and nothing otherwise. Sum these contributions over every place f≤n.
- Zero needs separate handling because leading zeros are not written. When higher>0, use (higher−1)f instead of higher×f, then add f or lower+1 according to current. Add one at the start for the number 0 itself.
- For digit 3 up to 42, the units place contributes four occurrences in 3,13,23,33. The tens place contributes ten in 30…39. The total is 14. Number 33 correctly contributes twice.
Why it works
For a fixed position the decimal representations cycle in blocks of 10f; each nonzero digit occupies exactly f numbers in a complete block, and the final partial block has the stated size. Removing the first zero block excludes all leading zeros. Each written digit belongs to exactly one position, so summing position counts gives the total.
Watch out. Count 0 itself once when k=0, exclude leading zeros, and include n. Avoid floating-point powers and avoid multiplying the final place by 10.
Commented C++17 solution
An independently written complete program with standard headers.
#include<iostream>
using namespace std;
int main(){
int target;
long long n;
cin>>target>>n;
long long answer=target==0?1:0;
for(long long place=1;place<=n;){
long long higher=n/place/10;
int current=int(n/place%10);
long long lower=n%place;
if(target!=0){
answer+=higher*place;
if(current>target){
answer+=place;
}
else if(current==target){
answer+=lower+1;
}
}
else if(higher>0){
// Remove the cycle that would write a leading zero.
answer+=(higher-1)*place;
answer+=current==0?lower+1:place;
}
if(place>n/10){
break;
}
place*=10;
}
cout<<answer<<'\n';
}