Кількість одиниць#44

Кількість одиниць (Розбір)

Нехай — мінімальна кількість одиниць, за допомогою яких можна представити число . Очевидно, що f(1) = 1.

Число можна представити тільки як суму двох одиниць: 2 = 1 + 1. Тому f(2) = 2. Аналогічно, число представляється тільки у вигляді суми трьох одиниць: 3 = 1 + 1 + 1. Тому f(3) = 3.

Число можна записати або як суму чотирьох одиниць: 4 = 1 + 1 + 1 + 1, або як добуток: 4 = (1 + 1) \cdot (1 + 1). Однак в обох випадках використовується одиниці, тому f(4) = 4.

Розглянемо вираз, значення якого дорівнює .

1. Припустимо, що останньою виконаною операцією є додавання. Нехай один доданок дорівнює і складається з одиниць, а другий доданок дорівнює n - i і складається з f(n - i) одиниць. Тоді значення слід вибрати так, щоб сума f(i) + f(n - i) була мінімальною.

При цьому значення достатньо перебирати до , оскільки можна вважати, що перший доданок не перевищує другий. Таким чином, отримуємо наступне співвідношення:

f(n) = \min_{1 \le i \le n/2} (f(i)+f(n - i))

2. Нехай останньою виконаною операцією було множення. Припустимо, що перший множник складається з одиниць, а другий множник складається з одиниць. Цей випадок має місце, якщо ділиться на без остачі.

Значення слід вибрати так, щоб сума f(i) + f(n / i) була мінімальною. При цьому достатньо перебирати значення в діапазоні від до \lfloor \sqrt{n} \rfloor. Таким чином, отримуємо наступне співвідношення:

f(n) = \min_{1 \le i \le \sqrt{n}} (f(i)+f(n/i))

Таким чином

f(n) = \min\left( \min_{1 \le i \le n/2} \bigl(f(i) + f(n - i)\bigr),\; \min_{1 \le i \le \sqrt{n}} \bigl(f(i) + f(n / i)\bigr) \right)

Приклад

Обчислимо відповідь для n = 7:

f(7) = f(6) + f(1) = (f(2) + f(3)) + f(1) = 2 + 3 + 1 = 6

Число можна представити за допомогою одиниць, а саме:

7 = (1 + 1) \cdot (1 + 1 + 1) + 1

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

Оголосимо масив .

int res[5001];

Зчитуємо вхідне значення .

scanf("%d",&n);

Ініціалізуємо res[1] = 1.

res[1] = 1;

Далі послідовно обчислимо значення res[2], res[3], ..., res[n] за наведеною вище формулою.

for (i = 2; i <= n; i++)
{
  res[i] = i;
  for (j = 1; 2 * j < i; j++)
    if (res[j] + res[i - j] < res[i]) res[i] = res[j] + res[i - j];
  for (j = 2; j * j <= i; j++)
    if (i % j == 0) 
      if (res[j] + res[i / j] < res[i]) res[i] = res[j] + res[i / j];
}

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

printf("%d\n",res[n]);