Коровы подсели
на новую игру в слова, называемую "Муу". В нее играют несколько
коров, стоящих в линию. Каждая корова должна назвать одну определенную букву
как можно быстрее. Корова, которая ошибется, выбывает из игры.
Последовательность
букв в игре Муу бесконечна. Начинается она так:
m o o m
o o o m o o m o o o o m o o m o o o m o o m o o o o o
Наилучшим
образом последовательность задается рекурсивно: пусть S(0) – слово из 3-х букв
"m o o". Последовательность S(k) получается из копии последовательности
S(k – 1), слова "m o ... o" с k + 2
буквами o, за которым следует еще одна копия последовательности S(k – 1). Например:
S(0) = "m o o"
S(1) = "m o o m o o o m o o"
S(2) = "m o o m o o o m o o m o o o o m o o m o o o m o o"
Можно заметить,
что таким образом строится бесконечно длинная строка, и именно она используется
в игре Муу. Бесси, мудрая корова, хочет узнать n – ую букву этой последовательности: какой она будет –
"m" или "o"? Помогите ей узнать это!
Вход. Одно целое число n
(1 ≤ n ≤ 109).
Выход. Одна буква – m
или o.
Пример
входа |
Пример
выхода |
11 |
m |
рекурсия
Ищем наименьшее k, для которого S(k) содержит n-ую букву.
Далее определяем, в какой из трех частей S(k)
лежит n-ая буква. Она лежит либо во
второй части (посередине), либо в третьей (в этом случае положим m равным сумме длин первой и второй
частей и запустим поиск (n – m)-ой буквы в S(k – 1), так как третья часть S(k)
полностью совпадает с S(k – 1)).
Пример
Пусть необходимо
определить n = 20 -ую букву.
Поскольку длина S(2) равна 10, а
длина S(3) равна 25, то 20-ая буква лежит в S(3).
20-ая буква
лежит в третьей части S(3), равной S(2). Следовательно 20-ая буква будет такой
же, как и 20 – 15 = 5-ая буква S(2).
Функция len(k) возвращает длину последовательности
S(k).
int len(int
k)
{
if (k == -1) return 0;
int x = len(k
- 1);
return x + k
+ 3 + x;
}
Поиск n-ой буквы в последовательности S(k).
char Solve(int
n, int k)
{
Если длина S(k) меньше
чем n, то следует искать n-ую букву в S(k + 1).
if (n >
len(k)) return Solve(n,k+1);
Если n не больше
длины S(k – 1), то следует искать n-ую букву в S(k – 1).
if (n <=
len(k-1)) return Solve(n,k-1);
Поскольку n > len(k – 1), то n-ую букву следует искать или
посередине, или во второй части S(k).
n = n - len(k-1);
Проверим, лежит ли n-ая буква в средней части
последовательности S(k).
if (n <= k
+ 3)
return (n
== 1) ? 'm' : 'o';
n-ая буква находится в последней
части S(k). Это все равно что искать ее в последовательности S(k – 1).
n = n - (k + 3);
return
Solve(n,k-1);
}
Основная часть программы. Начинаем искать n-ую букву в S(0).
scanf("%d",&n);
printf("%c\n",Solve(n,0));
Java реализация
import
java.util.*;
public class
Main
{
static int len(int k)
{
if (k ==
-1) return 0;
int x =
len(k - 1);
return x +
k + 3 + x;
}
static char Solve(int n, int k)
{
if (n >
len(k)) return Solve(n,k+1);
if (n <=
len(k-1)) return Solve(n,k-1);
n = n - len(k-1); /*
Discount S(k-1) from beginning of string */
if (n <=
k+3) /* n in middle section? */
return (n
== 1) ? 'm' : 'o';
n = n - (k+3);
return
Solve(n,k-1);
}
public static void
main(String[] args)
{
Scanner con = new
Scanner(System.in);
int n =
con.nextInt();
System.out.println(Solve(n,0));
con.close();
}
}