7438. Бинарный пароль

 

Жомарт использует двоичную строку в качестве пароля для своего компьютера. Недавно он забыл свой старый пароль и теперь хочет получить новый, который будет бинарной строкой длины n. Он считает пароль достаточно надёжным, если в нём не встречаются два последовательных нуля.

Чтобы получить новый пароль, Жомарт генерирует случайную двоичную строку длины n. Если строка не является надёжной, он генерирует новую строку и повторяет процесс до тех пор, пока не получит надёжный пароль.

Найдите ожидаемое количество случайно сгенерированных паролей, которое потребуется Жомарту, прежде чем он найдёт надёжный.

 

Вход. Одно целое число n (1 ≤ n ≤ 60).

 

Выход. Выведите ожидаемое значение в виде дроби p / q, где p и q – взаимно простые натуральные числа.

 

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

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

1

1/1

 

 

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

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

4

2/1

 

 

РЕШЕНИЕ

математика

 

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

Пароль (строка длины n) считается надёжным, если в нём не встречаются два последовательных нуля. Количество таких строк равно числу Фибоначчи fn, определяемому следующим образом:

f1 = 2 (строки 0, 1),

f2 = 3 (строки 01, 10, 11),

fn = fn-1 + fn-2, n > 3

Например, первые числа последовательности Фибоначчи имеют вид:

Общее количество бинарных строк длины n равно 2n. Таким образом, ожидаемое число случайно сгенерированных строк до нахождения надёжной равно

2n / fn

Указанную дробь следует сократить, разделив числитель и знаменатель на их наибольший общий делитель.

 

Пример

Для n = 1 ответ равен 21 / f1 = 2 / 2 = 1 / 1.

Для n = 4 ответ равен 24 / f4 = 16 / 8 = 2 / 1.

 

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

Объявим массив для хранения чисел Фибоначчи.

 

long long f[61];

 

Функция gcd вычисляет наибольший общий делитель двух чисел.

 

long long gcd(long long a, long long b)

{

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

}

 

Основная часть программы. Читаем входное значение n.

 

scanf("%d", &n);

 

Вычисляем числа Фибоначчи.

 

f[0] = 1; f[1] = 2;

for (i = 2; i <= n; i++)

  f[i] = f[i - 1] + f[i - 2];

 

Ответ равен дроби

num / den = 2n / fn

Сокращаем эту дробь, разделив числитель и знаменатель на их наибольший общий делитель.

 

num = (1LL << n);

den = f[n];

d = gcd(num, den);

 

num /= d;

den /= d;

 

Выводим ответ.

 

printf("%lld/%lld\n", num, den);