Матч 458, Произведение троек (ProductTriplet)

Дивизион 2, Уровень 3

 

Заданы шесть целых чисел minx, maxx, miny, maxy, minz и maxz. Вернуть количество троек (x, y, z), которые удовлетворяют следующим условиям:

·        x находится между minx и maxx включительно

·        y находится между miny и maxy включительно

·        z находится между minz и maxz включительно

·        x * y = z

 

Класс: ProductTriplet

Метод: countTriplets(int minx, int maxx, int miny, int maxy,

                     int minz, int maxz)

Ограничения: 1 £ maxx, maxy, maxz £ 109, 1 £ minx £ maxx, 1 £ miny £ maxy, 1 £ minz £ maxz.

 

Вход. Шесть целых чисел minx, maxx, miny, maxy, minz и maxz.

 

Выход. Количество троек (x, y, z), удовлетворяющих выше перечисленным условиям.

 

Пример входа

minx

maxx

miny

maxy

minz

maxz

2

2

3

3

6

6

2

2

3

3

7

7

6

8

4

5

27

35

 

Пример выхода

1

0

4

 

 

РЕШЕНИЕ

математика

 

Рассмотрим частный случай задачи. Пусть значение x0 фиксировано. Вычислим количество троек (x0, y, z), для которых

minyymaxy, minzzmaxz и x0 * y = z

Выведем ограничения на y:

minzx0 * ymaxz, minz / x0ymaxz / x0,

Объединим последнее ограничение y на с minyymaxy, получим:

Поскольку любое целое значение y из указанного интервала порождает искомую тройку (x0, y, z), то количество последних при фиксированном x0 равно

при условии, что указанная разница неотрицательна (иначе интервал y пуст).

Остается перебрать все значения minxx0maxx и подсчитать количество троек для каждого из них. Однако такое решение не пройдет по времени.

Решения уравнения x * y = z будем искать отдельно для каждого из следующих случаев:

·        x = y = ; (1)

·         и таким образом ; (2)

·         и таким образом ; (3)

Тройки решений (x, y, z) во всех трех случаях не пересекаются.

Количество троек, для которых выполняется (1), равно количеству чисел из интервала , не меньших  и не больших .

Для нахождения троек, удовлетворяющих (2), будем следовать выше описанному алгоритму, только перебор по x0 будем делать не только от minx до maxx, а еще и с условием . То есть minxx0 ≤ min (maxx, ).

Аналогично при нахождении троек, удовлетворяющих (3), будем совершать перебор y0 так, что minyy0 ≤ min (maxy, ).

 

ПРОГРАММА

 

 

#include <stdio.h>

 

int min(int x, int y)

{

  return (x < y) ? x : y;

}

int max(int x, int y)

{

  return (x > y) ? x : y;

}

 

long long f(long long x0, long long miny, long long maxy,

            long long minz, long long maxz)

{

  // x0 < sqrt(z), x0^2 < z, z >= x0 * x0 + 1

  minz = max(minz, x0 * x0 + 1);

  if (maxz < minz) return 0;

  miny = max(miny, (minz + x0 - 1) / x0);

  maxy = min(maxy, maxz / x0);

  return max(0LL, maxy - miny + 1);

}

 

class ProductTriplet

{

public:

  long long countTriplets(int minx, int maxx, int miny, int maxy,

                          int minz, int maxz)

  {

    long long x0, y0, i, res = 0;

    // x < sqrt(z);

    for(x0 = minx; (x0 <= maxx) && (x0 * x0 < maxz); x0++)

      res += f(x0,miny,maxy,minz,maxz);

    // y < sqrt(z);

    for(y0 = miny; (y0 <= maxy) && (y0 * y0 < maxz); y0++)

      res += f(y0,minx,maxx,minz,maxz);

    for(i = max(minx,miny); (i <= min(maxx,maxy)) && (i * i <= maxz); i++)

      if (minz <= i * i) res ++;

    return res;

  }

};

 

int main(void)

{

  ProductTriplet p;

  //long long res = p.countTriplets(6,8,4,5,27,35);

  //long long res = p.countTriplets(2,2,3,3,7,7);

  long long res = p.countTriplets(8176,184561,1348,43168,45814517,957843164);

  printf("%lld\n",res);

  return 0;

}