cppAcademy
FROM LEARNING TO COMPETING

Real problems.
Your next challenge.

Explore the Group C Olympiad and Autumn Tournament archive.
Choose a topic. Find a challenge. Build your solution.

274 tasks: 213 from the Municipal, Regional, and National Olympiad rounds (2009–2026), 57 Autumn Tournament tasks (2007–2025), and 4 previously featured problems. 207 tasks have independently written English summaries, analyses, and C++17 solutions; the remaining entries link to Arena. Difficulty labels are learning estimates, not official ratings. Special formats and source clarifications are explained on affected tasks.
GROUP C2010 · MediumDigit counting and permutations

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

  1. 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.
  2. 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.
  3. 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.
  4. 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.

Complexity: O(|A|+|B|+10²) time and O(|A|+|B|) storage for the endpoint strings; the counting work beyond reading uses at most ten positions and ten digit choices per position. Auxiliary space beyond input is O(1).

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';
}

Source: Arena Olimpiici ↗