TRAVELJO - Editorial

PROBLEM LINK: CodeChef: Practical coding for everyone

Author: Viknesh R
Tester: John Zakkam
Editorialist: Viknesh R

DIFFICULTY:

EASY

PREREQUISITES:

Math, Binary Search

PROBLEM:

After defending The Wall from the White Walkers, Jon Snow needs to head back to King’s Landing and Winterfell to avenge his father’s death. Jon Snow has a map in his hand but he realizes that the map is too old to be read. Therefore, Jon Snow comes up with a plan. He calculates a number called N-th Travel Number and using this number, he finds his way to King’s Landing. Help Jon Snow to calculate N-th Travel Number.

A number is said to be a Travel Number if it is divisible by either A or B.

Since the Travel Number can be large, output the number modulo (10^9 + 7).

EXPLANATION:

Say L=lcm(A,B), the least common multiple of A and B; and let f(x) be the number of magical numbers less than or equal to x. A well known result says that L = \frac{A * B}{\text{gcd}(A, B)}, and that we can calculate the function \gcd.

Then f(x) = \lfloor \frac{x}{A} \rfloor + \lfloor \frac{x}{B} \rfloor - \lfloor \frac{x}{L} \rfloor. Why? There are \lfloor \frac{x}{A} \rfloor numbers A, 2A, 3A, \cdots that are divisible by A, there are \lfloor \frac{x}{B} \rfloor numbers divisible by B, and we need to subtract the \lfloor \frac{x}{L} \rfloor numbers divisible by A and B that we double counted.

Finally, the answer must be between 0 and N * \min(A, B).
Without loss of generality, suppose A \geq B, so that it remains to show

\lfloor \frac{N * \min(A, B)}{A} \rfloor + \lfloor \frac{N * \min(A, B)}{B} \rfloor - \lfloor \frac{N * \min(A, B)}{\text{lcm}(A, B)} \rfloor \geq N

\Leftrightarrow \lfloor \frac{N*A}{A} \rfloor + \lfloor \frac{N*A}{B} \rfloor - \lfloor \frac{N*A*\gcd(A, B)}{A*B} \rfloor \geq N

\Leftrightarrow \lfloor \frac{N*A}{B} \rfloor \geq \lfloor \frac{N*\gcd(A, B)}{B} \rfloor

\Leftrightarrow A \geq \gcd(A, B)

SOLUTIONS:

Setter's Solution
#include <bits/stdc++.h>

using namespace std;

const int MOD = 1e9 + 7;

int gcd(int x, int y)
{
    if(x == 0)
    {
        return y;
    }
    return gcd(y % x, x);
}

int nth_travel_number(int n, int a, int b)
{
    int lcm = a / gcd(a, b) * b;
    long int low = 0;
    long int high = (long) n * min(a,b);

    while(low < high)
    {
        long mid = low + (high - low) / 2;

        if(mid / a + mid / b - mid / lcm < n)
        {
            low = mid + 1;
        }
        else
        {
            high = mid;
        }
    }
    return (int) (low % MOD);
}

int main()
{
    int t;
    cin >> t;
    int n[t], a[t], b[t];

    for(int i = 0; i < t; ++i)
    {
        cin >> n[i] >> a[i] >> b[i];
    }

    for(int i = 0; i < t; ++i)
    {
        cout << nth_travel_number(n[i], a[i], b[i]) << endl;
    }
    return 0;
}