Рядки Фібоначчі#2524

Рядки Фібоначчі (Розбір)

Фібоначчієві рядки визначаються рекурентно:

F_n = F_{n-2} + F_{n-1}

Це означає, що рядок F_n складається з двох частин:

Отже, щоб знайти -й символ рядка F_n, не потрібно будувати весь рядок. Достатньо визначити, в якій з двох частин він знаходиться.

Позначимо через F_n(k) -ий символ рядка F_n.

Тоді:

F_n(k) = F_{n-2}(k)
F_n(k) = F_{n-1}(k - |F_{n-2}|)

Таким чином, задача зводиться до пошуку символа в рядках з меншими індексами.

Приклад

Розглянемо рядок F_6, для якого мають місце співвідношення:

Обчислимо F_6(4). Оскільки k = 4 \le |F_4| = 5, то F_6(4) = F_4(4).

Обчислимо F_6(7). Оскільки k = 7 > |F_4| = 5, то F_6(7) = F_5(7 - 5) = F_5(2).

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

У масиві зберігаються довжини фібоначчієвих рядків:

#define MAX 44
int fib[MAX] = {1, 1};

Функція solve повертає -й символ рядка F_n, не будучи сам рядок цілком.

char solve(int n, int k)
{

Окремо оброблюємо базові випадки n = 0 і n = 1.

  if (n == 0) return 'a';
  if (n == 1) return 'b';

Відомо, що F_n = F_{n - 2} + F_{n - 1}.

  if (k <= fib[n-2]) return solve(n - 2, k);
  return solve(n - 1, k - fib[n-2]);
}

Основна частина програми. Обчислюємо перші числа Фібоначчі.

for (int i = 2; i < MAX; i++)
  fib[i] = fib[i-1] + fib[i-2];

Читаємо кількість тестів .

scanf("%d",&tests);
while (tests--)
{

Обчислюємо і виводимо відповідь для кожного тесту.

  scanf("%d %d",&n,&k);
  printf("%c\n",solve(n,k));
}