Простий поділ#1182

Простий поділ (Розбір)

  1. Розгляньте другий тест. Чому рівні остачі при діленні кожного числа на ?

  2. Розгляньте третій тест. Чому рівні остачі при діленні кожного числа на ? Згадайте, як обчислюються остачі при діленні від'ємних чисел на додатні.

  3. Нехай — найбільше число, для якого при діленні всіх чисел a_i на отримуються однакові остачі. Що можна сказати про різницю будь-яких двох чисел послідовності відносно числа ?

  4. Подайте числа a_i у вигляді a_i = d \cdot r_i + rest і розгляньте різниці a_{i+1} - a_i. Якому найбільшому значенню задовольняють ці рівняння? Згадайте визначення найбільшого спільного дільника.

Аналіз алгоритму

Нехай дана послідовність чисел: a_1, a_2, ..., a_k.

Якщо при діленні кожного числа a_i~(1 \le i \le k) на остача однакова, позначимо цю остачу як . Тоді кожне число можна записати у вигляді:

a_1 = d \cdot r_1 + rest \\ a_2 = d \cdot r_2 + rest \\ ... \\ a_k = d \cdot r_k + rest

Тут r_1, r_2, ..., r_k — цілі числа (частки від ділення).

Тепер вирахуємо сусідні елементи послідовності:

a_2 - a_1 = d \cdot (r_2 - r_1) \\ a_3 - a_2 = d \cdot (r_3 - r_2) \\ ... \\ a_k - a_{k-1} = d \cdot (r_k - r_{k-1})

У всіх цих різницях число є множником. Значить, ділить кожну з різниць: a_2 - a_1, a_3 - a_2, ..., a_k - a_{k-1}.

Ми шукаємо максимальне можливе , що ділить всі ці різниці. За визначенням, найбільше число, що ділить кілька чисел одночасно, — це їх найбільший спільний дільник (НСД). Отже

d = НСД(|a_2 - a_1|, |a_3 - a_2|, ..., |a_k - a_{k-1}|)

Оскільки вибрано максимальним, то числа r_2 - r_1, r_3 - r_2, ... не мають спільного дільника більше . Інакше цей спільний дільник можна було б винести, збільшивши , що суперечить його максимальності. Таким чином

НСД(r_1, r_2, ..., r_n) = 1

Зазначимо також, що якщо, наприклад, з кожного рівняння виду a_i = d \cdot r_i + rest~(2 \le i \le k) віднімемо перше, то відповідь можна записати у наступному вигляді:

d = НСД(|a_2 - a_1|, |a_3 - a_1|, ..., |a_k - a_1|)

Іноді обчислення в такому вигляді є більш зручними.

Приклад

Для першого тесту отримаємо:

d = НСД(|1059 - 701|, |1417 - 1059|, |2312 - 1417|) = НСД(358, 358, 895) = 179.

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

Функція gcd обчислює найбільший спільний дільник двох чисел і .

int gcd(int a, int b)
{
  return (!b) ? a : gcd(b, a % b);
}

Основна частина програми. Читаємо перше число a_1. Якщо воно дорівнює , значить це останній рядок і він не обробляється — виходимо з циклу.

while (scanf("%d", &a), a)
{

Змінна зберігає поточний результат — найбільший спільний дільник різниць.

  res = 0;

Читаємо чергове число рядка у змінну . Відповідь обчислюємо за формулою

d = НСД(|a_2 - a_1|, |a_3 - a_1|, ..., |a_k - a_1|)

У коді змінна зберігає значення a_1, а змінна приймає значення a_2, a_3, ..., a_k.

  while (scanf("%d", &b), b)
    res = gcd(res, abs(b - a));

Виводимо відповідь.

  printf("%d\n", res);
}