Count Numbers with Distinct Digits
Autumn Tournament (2010)
Submission name: unique.cpp
Problem summary
Count the positive integers in [A,B] whose decimal digits are all different. Numbers have no leading zeros; endpoints may contain up to 101 decimal digits.
Input
Two decimal integers A and B.
Output
The number of qualifying integers.
Constraints
1 ≤ A ≤ B ≤ 10^100.
Worked example
Original statement sample.
Input
1 100
Output
90
Solution analysis
- A valid positive integer can have at most ten digits. Instead of iterating over a potentially enormous interval, calculate F(X), the count of valid numbers at most X, and use F(B)−F(A)+[A is valid]. This avoids decrementing a hundred-digit decimal string.
- For a length L, there are 9·P(9,L−1) numbers: choose a nonzero first digit, then ordered distinct remaining digits. To count numbers with the same length as X, follow X left to right. At a position, try every unused smaller legal digit; each such choice contributes P(remaining available digits, remaining positions). Then follow the actual digit, stopping if it repeats.
- If X has more than ten digits, every distinct-digit number is smaller, so only the ten length counts are needed. Keep endpoints as strings and use a bitmask of ten used digits. All counts fit comfortably in long long.
- For [1,100], there are 9 one-digit and 9·9=81 two-digit numbers. The only three-digit candidate not exceeding 100 repeats zero, so F(100)=90 and the answer is 90.
Why it works
Every shorter valid number is counted by its unique sequence of distinct digits. A same-length number below X has a unique first position where its digit is smaller; the prefix scan counts precisely that branch, with all legal completions. The actual X is added only when all its digits are distinct. Subtracting the cumulative counts gives exactly the closed interval.
Watch out. Include A when it is valid. Do not allow a leading zero or count zero as a positive number. Do not parse a 10^100 endpoint into an integer. Repeated digits terminate only the equal-prefix branch, not previously counted smaller branches.
Commented C++17 solution
An independently written complete program with standard headers.
#include<iostream>
#include<string>
using namespace std;
long long permutations(int available,int places){
long long result=1;
for(int i=0;i<places;i++){
result*=available-i;
}
return result;
}
bool distinctDigits(const string&number){
if(number.size()>10){
return false;
}
int used=0;
for(char symbol:number){
int digit=symbol-'0';
if((used&(1<<digit))!=0){
return false;
}
used|=1<<digit;
}
return true;
}
long long countAtMost(const string&bound){
int length=static_cast<int>(bound.size());
long long answer=0;
for(int digits=1;digits<length&&digits<=10;digits++){
answer+=9*permutations(9,digits-1);
}
if(length>10){
return answer;
}
int used=0;
for(int position=0;position<length;position++){
int current=bound[position]-'0';
int first=position==0?1:0;
for(int digit=first;digit<current;digit++){
if((used&(1<<digit))==0){
// Once this digit is smaller, all distinct completions qualify.
answer+=permutations(9-position,length-position-1);
}
}
if((used&(1<<current))!=0){
return answer;
}
used|=1<<current;
}
return answer+1;
}
int main(){
string a;
string b;
cin>>a>>b;
cout<<countAtMost(b)-countAtMost(a)+distinctDigits(a)<<'\n';
}