Кількість чисел виду 2^x * 3^y#9021

Кількість чисел виду 2^x * 3^y (Розбір)

Чисел виду 2^x * 3^y, які не перевищують 10^{18}, не так вже й багато. Згенеруємо їх і збережемо в масиві .

Кількість шуканих чисел f(a, b) на відрізку можна знайти за формулою:

f(0, b) - f(0, a - 1)

Тут f(0, q) позначає кількість чисел виду 2^x * 3^y, які не перевищують . Відповідь на цей запит можна знайти за допомогою бінарного пошуку на масиві .

Приклад

Згенеруємо всі числа виду 2^x * 3^y, які не перевищують .

Відрізку належить чисел (виділені синім).

Відрізку належить чисел (виділені зеленим).

Знайдемо розв'язання для відрізка :

upper\_bound(v.begin(), v.end(), 20) - upper\_bound(v.begin(), v.end(), 9) = 3

Дійсно, відрізку належать числа шуканого виду:

12, 16, 18

Реалізація алгоритму

Оголосимо константу MAX = 10^{18} і робочий масив .

#define MAX 1000000000000000000LL
vector<long long> v;

Функція preprocess генерує всі числа виду 2^x * 3^y, які не перевищують 10^{18}, і зберігає їх у масиві . Для кожного значення x = 1, 2, 4, 8, ... перебираємо числа y = 1, 3, 9, 27, ... доти, поки x * y < MAX.

void preprocess()
{
  long long x = 1, y = 1;
  while (x < MAX)
  {
    while (x * y < MAX)
    {
      v.push_back(x * y);
      y *= 3;
    }
    x *= 2;
    y = 1;
  }

Відсортуємо числа у масиві .

  sort(v.begin(), v.end());
}

Основна частина програми. Генеруємо масив чисел виду 2^x * 3^y.

preprocess();

Читаємо запит — відрізок . Кількість шуканих чисел на цьому відрізку обчислюється за формулою:

f(a, b) = f(0, b) - f(0, a - 1)
while (scanf("%lld %lld", &a, &b) == 2)
{
  res = upper_bound(v.begin(), v.end(), b) – upper_bound(v.begin(), v.end(), a - 1);
  printf("%lld\n", res);
}