ЕГЭ по информатике · задание 12

Исполнитель МТ: машина Тьюринга

Головка движется по ленте с нулями и единицами и меняет символы по таблице команд. Нужно понять, что делает программа, и найти наибольшее или наименьшее возможное число нулей или единиц в исходной последовательности.

Как читать таблицу

  • Строка — состояние, столбец — символ под головкой.
  • Команда «0, L, q1»: записать 0, сдвинуться влево, перейти в q1.
  • S — остановка после записи символа.

Как решать

  1. Прогнать программу на короткой ленте (5–8 символов) на бумаге.
  2. Сформулировать, что машина делает с последовательностью.
  3. Связать числа нулей и единиц до и после и найти крайний случай.
  4. Проверить крайний случай моделированием.

Типичные ошибки

  • Забыть, что машина может остановиться раньше конца последовательности.
  • Перепутать направление: головка начинает справа.
  • Не учесть ограничение на длину последовательности.

Разобранные варианты

Сначала прогони программу на короткой ленте и найди закономерность, потом открой разбор.

Вариант 1

вычитание единицы · максимум

Исполнитель МТ — головка, которая движется вдоль бесконечной ленты из ячеек; в каждой ячейке записан ровно один символ алфавита, в том числе пустой символ λ. За один такт головка в состоянии q, обозревая символ в текущей ячейке, выполняет команду из таблицы: записывает символ, затем сдвигается влево (L), вправо (R), остаётся на месте (N) или останавливается (S), и переходит в новое состояние. Команда «1, L, q1» означает: записать 1, сдвинуться влево, перейти в состояние q1. В начальный момент головка находится в состоянии q0.

На ленте в соседних ячейках записана последовательность из 1000 символов, включающая только нули и единицы. Ячейки справа и слева от последовательности заполнены пустыми символами «λ». В начальный момент головка расположена в ближайшей ячейке справа от последовательности.

Программа работы исполнителя:

λ10
q0λ, L, q1
q1λ, S, q10, S, q11, L, q1

После выполнения программы на ленте осталось ровно 312 нулей. Определите максимально возможное число нулей в исходной последовательности.

Разбор

Шаг 1. Что делает программа. В состоянии q0 головка на пустой ячейке сдвигается влево — на последний символ последовательности. Головка идёт влево от конца последовательности. Каждый 0 заменяется на 1, пока не встретится 1; эта единица заменяется на 0, и машина останавливается. Если записать последовательность как A10…0 (в конце t нулей), получится A01…1 — это вычитание единицы из двоичного числа.

Шаг 2. Считаем. Пусть в конце t нулей перед единицей: A10…0 → A01…1. Нули после работы — нули части A и ещё один (бывшая 1): z(A) + 1 = 312, значит z(A) = 311. Нулей было z(A) + t = 311 + t. Длина A равна 1000 − 1 − t и не меньше z(A), откуда t ≤ 1000 − 1 − 311 = 688. Наибольшее число нулей: 311 + 688 = 999.

Пример крайней ленты (сжато: «0×5» — пять нулей подряд, «(01)×3» — 010101): 0×311 1 0×688. После работы: 0×312 1×688.

Ответ: 999

Проверка на Python. Перебрать все ленты из тысячи символов нельзя, поэтому программа моделирует МТ и проверяет крайний случай из рассуждения: печатает число символов после работы и в исходной ленте.

L = 'λ'
prog = {
    ('q0', 'λ'): ('λ', 'L', 'q1'),
    ('q1', 'λ'): ('λ', 'S', 'q1'),
    ('q1', '1'): ('0', 'S', 'q1'),
    ('q1', '0'): ('1', 'L', 'q1'),
}

def run(seq):
    tape = dict(enumerate(seq))
    pos, st = len(seq), 'q0'          # головка справа от последовательности
    while True:
        w, mv, st2 = prog[(st, tape.get(pos, L))]
        tape[pos] = w
        st = st2
        if mv == 'S':
            return ''.join(c for k, c in sorted(tape.items()) if c != L)
        pos += -1 if mv == 'L' else 1

# крайний случай из рассуждения
seq = '0' * 311 + '1' * 1 + '0' * 688
after = run(seq)
print(after.count('0'))       # должно быть 312
print(seq.count('0'))

Вариант 2

инверсия через один · максимум

Исполнитель МТ — головка, которая движется вдоль бесконечной ленты из ячеек; в каждой ячейке записан ровно один символ алфавита, в том числе пустой символ λ. За один такт головка в состоянии q, обозревая символ в текущей ячейке, выполняет команду из таблицы: записывает символ, затем сдвигается влево (L), вправо (R), остаётся на месте (N) или останавливается (S), и переходит в новое состояние. Команда «1, L, q1» означает: записать 1, сдвинуться влево, перейти в состояние q1. В начальный момент головка находится в состоянии q0.

На ленте в соседних ячейках записана последовательность из 1500 символов, включающая только нули и единицы. Ячейки справа и слева от последовательности заполнены пустыми символами «λ». В начальный момент головка расположена в ближайшей ячейке справа от последовательности.

Программа работы исполнителя:

λ01
q0λ, L, q1
q1λ, S, q11, L, q20, L, q2
q2λ, S, q20, L, q11, L, q1

После выполнения программы на ленте осталось ровно 1112 нулей. Определите максимально возможное число нулей в исходной последовательности.

Разбор

Шаг 1. Что делает программа. В состоянии q0 головка на пустой ячейке сдвигается влево — на последний символ последовательности. Состояния q1 и q2 чередуются: в q1 символ инвертируется (0 ↔ 1), в q2 остаётся прежним. Значит, если нумеровать символы справа налево, меняются все символы на нечётных местах, а на чётных — остаются.

Шаг 2. Считаем. Пронумеруем символы справа налево. Нечётных мест 750, чётных 750. Пусть на нечётных местах было a нулей, на чётных — b. После работы нули на нечётных местах станут единицами и наоборот: нулей станет (750 − a) + b = 1112, то есть b = a + 362. Было нулей a + b = 2a + 362. Чтобы это было наибольшим, берём a как можно больше: a ≤ 750 и b = a + 362 ≤ 750, значит a = 388, b = 750. Ответ: 388 + 750 = 1138.

Пример крайней ленты (сжато: «0×5» — пять нулей подряд, «(01)×3» — 010101): (01)×362 0×776. После работы: 0×725 (10)×387 1.

Ответ: 1138

Проверка на Python. Перебрать все ленты из тысячи символов нельзя, поэтому программа моделирует МТ и проверяет крайний случай из рассуждения: печатает число символов после работы и в исходной ленте.

L = 'λ'
prog = {
    ('q0', 'λ'): ('λ', 'L', 'q1'),
    ('q1', 'λ'): ('λ', 'S', 'q1'),
    ('q1', '0'): ('1', 'L', 'q2'),
    ('q1', '1'): ('0', 'L', 'q2'),
    ('q2', 'λ'): ('λ', 'S', 'q2'),
    ('q2', '0'): ('0', 'L', 'q1'),
    ('q2', '1'): ('1', 'L', 'q1'),
}

def run(seq):
    tape = dict(enumerate(seq))
    pos, st = len(seq), 'q0'          # головка справа от последовательности
    while True:
        w, mv, st2 = prog[(st, tape.get(pos, L))]
        tape[pos] = w
        st = st2
        if mv == 'S':
            return ''.join(c for k, c in sorted(tape.items()) if c != L)
        pos += -1 if mv == 'L' else 1

# крайний случай из рассуждения
seq = '01' * 362 + '0' * 776
after = run(seq)
print(after.count('0'))       # должно быть 1112
print(seq.count('0'))

Вариант 3

прореживание единиц · максимум

Исполнитель МТ — головка, которая движется вдоль бесконечной ленты из ячеек; в каждой ячейке записан ровно один символ алфавита, в том числе пустой символ λ. За один такт головка в состоянии q, обозревая символ в текущей ячейке, выполняет команду из таблицы: записывает символ, затем сдвигается влево (L), вправо (R), остаётся на месте (N) или останавливается (S), и переходит в новое состояние. Команда «1, L, q1» означает: записать 1, сдвинуться влево, перейти в состояние q1. В начальный момент головка находится в состоянии q0.

На ленте в соседних ячейках записана последовательность из 1200 символов, включающая только нули и единицы. Ячейки справа и слева от последовательности заполнены пустыми символами «λ». В начальный момент головка расположена в ближайшей ячейке справа от последовательности.

Программа работы исполнителя:

λ01
q0λ, L, q1
q1λ, S, q10, L, q11, L, q2
q2λ, S, q20, L, q10, L, q1

После выполнения программы на ленте осталось ровно 431 единица. Определите максимально возможное число единиц в исходной последовательности.

Разбор

Шаг 1. Что делает программа. В состоянии q0 головка на пустой ячейке сдвигается влево — на последний символ последовательности. Состояние q2 означает «предыдущий (правее) символ — сохранённая единица». Если в q2 снова встречается 1, она стирается в 0. Поэтому в каждой группе подряд идущих единиц длины r, считая справа, единицы через одну заменяются нулями: остаётся ⌈r / 2⌉ единиц.

Шаг 2. Считаем. Группа из r единиц даёт ⌈r / 2⌉ единиц. На одну оставшуюся единицу приходится не больше двух исходных (группа чётной длины 2m даёт ровно m). Поэтому исходных единиц не больше 2·431 = 862; столько получается, например, у ленты из 338 нулей и 862 единиц подряд (862 ≤ 1200).

Пример крайней ленты (сжато: «0×5» — пять нулей подряд, «(01)×3» — 010101): 0×338 1×862. После работы: 0×339 (10)×430 1.

Ответ: 862

Проверка на Python. Перебрать все ленты из тысячи символов нельзя, поэтому программа моделирует МТ и проверяет крайний случай из рассуждения: печатает число символов после работы и в исходной ленте.

L = 'λ'
prog = {
    ('q0', 'λ'): ('λ', 'L', 'q1'),
    ('q1', 'λ'): ('λ', 'S', 'q1'),
    ('q1', '0'): ('0', 'L', 'q1'),
    ('q1', '1'): ('1', 'L', 'q2'),
    ('q2', 'λ'): ('λ', 'S', 'q2'),
    ('q2', '0'): ('0', 'L', 'q1'),
    ('q2', '1'): ('0', 'L', 'q1'),
}

def run(seq):
    tape = dict(enumerate(seq))
    pos, st = len(seq), 'q0'          # головка справа от последовательности
    while True:
        w, mv, st2 = prog[(st, tape.get(pos, L))]
        tape[pos] = w
        st = st2
        if mv == 'S':
            return ''.join(c for k, c in sorted(tape.items()) if c != L)
        pos += -1 if mv == 'L' else 1

# крайний случай из рассуждения
seq = '0' * 338 + '1' * 862
after = run(seq)
print(after.count('1'))       # должно быть 431
print(seq.count('1'))

Вариант 4

пары «01» · максимум

Исполнитель МТ — головка, которая движется вдоль бесконечной ленты из ячеек; в каждой ячейке записан ровно один символ алфавита, в том числе пустой символ λ. За один такт головка в состоянии q, обозревая символ в текущей ячейке, выполняет команду из таблицы: записывает символ, затем сдвигается влево (L), вправо (R), остаётся на месте (N) или останавливается (S), и переходит в новое состояние. Команда «1, L, q1» означает: записать 1, сдвинуться влево, перейти в состояние q1. В начальный момент головка находится в состоянии q0.

На ленте в соседних ячейках записана последовательность из 1200 символов, включающая только нули и единицы. Ячейки справа и слева от последовательности заполнены пустыми символами «λ». В начальный момент головка расположена в ближайшей ячейке справа от последовательности.

Программа работы исполнителя:

λ01
q0λ, L, q1
q1λ, S, q10, L, q11, L, q2
q2λ, S, q21, L, q11, L, q2

После выполнения программы на ленте осталось ровно 515 нулей. Определите максимально возможное число нулей в исходной последовательности.

Разбор

Шаг 1. Что делает программа. В состоянии q0 головка на пустой ячейке сдвигается влево — на последний символ последовательности. Состояние q2 означает «правее стоит единица». Если в q2 встречается 0, он заменяется на 1. Поэтому каждый 0, стоящий сразу слева от группы единиц (то есть каждая пара «01»), превращается в 1, а остальные символы не меняются.

Шаг 2. Считаем. Каждая пара «01» теряет нуль. Если пар r, то нулей было Z = 515 + r. Для r пар нужно r нулей и r единиц, а единиц всего 1200 − Z, поэтому r ≤ 1200 − (515 + r), то есть 2r ≤ 685, r ≤ 342. Наибольшее Z = 515 + 342 = 857.

Пример крайней ленты (сжато: «0×5» — пять нулей подряд, «(01)×3» — 010101): 0×516 (10)×341 1×2. После работы: 0×515 1×685.

Ответ: 857

Проверка на Python. Перебрать все ленты из тысячи символов нельзя, поэтому программа моделирует МТ и проверяет крайний случай из рассуждения: печатает число символов после работы и в исходной ленте.

L = 'λ'
prog = {
    ('q0', 'λ'): ('λ', 'L', 'q1'),
    ('q1', 'λ'): ('λ', 'S', 'q1'),
    ('q1', '0'): ('0', 'L', 'q1'),
    ('q1', '1'): ('1', 'L', 'q2'),
    ('q2', 'λ'): ('λ', 'S', 'q2'),
    ('q2', '1'): ('1', 'L', 'q2'),
    ('q2', '0'): ('1', 'L', 'q1'),
}

def run(seq):
    tape = dict(enumerate(seq))
    pos, st = len(seq), 'q0'          # головка справа от последовательности
    while True:
        w, mv, st2 = prog[(st, tape.get(pos, L))]
        tape[pos] = w
        st = st2
        if mv == 'S':
            return ''.join(c for k, c in sorted(tape.items()) if c != L)
        pos += -1 if mv == 'L' else 1

# крайний случай из рассуждения
seq = '0' * 516 + '10' * 341 + '1' * 2
after = run(seq)
print(after.count('0'))       # должно быть 515
print(seq.count('0'))

Вариант 5

инверсия через один · минимум

Исполнитель МТ — головка, которая движется вдоль бесконечной ленты из ячеек; в каждой ячейке записан ровно один символ алфавита, в том числе пустой символ λ. За один такт головка в состоянии q, обозревая символ в текущей ячейке, выполняет команду из таблицы: записывает символ, затем сдвигается влево (L), вправо (R), остаётся на месте (N) или останавливается (S), и переходит в новое состояние. Команда «1, L, q1» означает: записать 1, сдвинуться влево, перейти в состояние q1. В начальный момент головка находится в состоянии q0.

На ленте в соседних ячейках записана последовательность из 1500 символов, включающая только нули и единицы. Ячейки справа и слева от последовательности заполнены пустыми символами «λ». В начальный момент головка расположена в ближайшей ячейке справа от последовательности.

Программа работы исполнителя:

λ01
q0λ, L, q1
q1λ, S, q11, L, q20, L, q2
q2λ, S, q20, L, q11, L, q1

После выполнения программы на ленте осталось ровно 931 нуль. Определите минимально возможное число нулей в исходной последовательности.

Разбор

Шаг 1. Что делает программа. В состоянии q0 головка на пустой ячейке сдвигается влево — на последний символ последовательности. Состояния q1 и q2 чередуются: в q1 символ инвертируется (0 ↔ 1), в q2 остаётся прежним. Значит, если нумеровать символы справа налево, меняются все символы на нечётных местах, а на чётных — остаются.

Шаг 2. Считаем. Пронумеруем символы справа налево. Нечётных мест 750, чётных 750. Пусть на нечётных местах было a нулей, на чётных — b. После работы нули на нечётных местах станут единицами и наоборот: нулей станет (750 − a) + b = 931, то есть b = a + 181. Было нулей a + b = 2a + 181. Чтобы это было наименьшим, берём a как можно меньше: b = a + 181 ≥ 0 и a ≥ 0, значит a = 0, b = 181. Ответ: 0 + 181 = 181.

Пример крайней ленты (сжато: «0×5» — пять нулей подряд, «(01)×3» — 010101): 1×1138 (01)×181. После работы: (10)×569 0×362.

Ответ: 181

Проверка на Python. Перебрать все ленты из тысячи символов нельзя, поэтому программа моделирует МТ и проверяет крайний случай из рассуждения: печатает число символов после работы и в исходной ленте.

L = 'λ'
prog = {
    ('q0', 'λ'): ('λ', 'L', 'q1'),
    ('q1', 'λ'): ('λ', 'S', 'q1'),
    ('q1', '0'): ('1', 'L', 'q2'),
    ('q1', '1'): ('0', 'L', 'q2'),
    ('q2', 'λ'): ('λ', 'S', 'q2'),
    ('q2', '0'): ('0', 'L', 'q1'),
    ('q2', '1'): ('1', 'L', 'q1'),
}

def run(seq):
    tape = dict(enumerate(seq))
    pos, st = len(seq), 'q0'          # головка справа от последовательности
    while True:
        w, mv, st2 = prog[(st, tape.get(pos, L))]
        tape[pos] = w
        st = st2
        if mv == 'S':
            return ''.join(c for k, c in sorted(tape.items()) if c != L)
        pos += -1 if mv == 'L' else 1

# крайний случай из рассуждения
seq = '1' * 1138 + '01' * 181
after = run(seq)
print(after.count('0'))       # должно быть 931
print(seq.count('0'))

Вариант 6

прибавление единицы · максимум

Исполнитель МТ — головка, которая движется вдоль бесконечной ленты из ячеек; в каждой ячейке записан ровно один символ алфавита, в том числе пустой символ λ. За один такт головка в состоянии q, обозревая символ в текущей ячейке, выполняет команду из таблицы: записывает символ, затем сдвигается влево (L), вправо (R), остаётся на месте (N) или останавливается (S), и переходит в новое состояние. Команда «1, L, q1» означает: записать 1, сдвинуться влево, перейти в состояние q1. В начальный момент головка находится в состоянии q0.

На ленте в соседних ячейках записана последовательность из 1200 символов, включающая только нули и единицы. Ячейки справа и слева от последовательности заполнены пустыми символами «λ». В начальный момент головка расположена в ближайшей ячейке справа от последовательности.

Программа работы исполнителя:

λ01
q0λ, L, q1
q11, S, q11, S, q10, L, q1

После выполнения программы на ленте осталось ровно 592 нуля. Определите максимально возможное число нулей в исходной последовательности.

Разбор

Шаг 1. Что делает программа. В состоянии q0 головка на пустой ячейке сдвигается влево — на последний символ последовательности. Головка идёт влево от конца последовательности. Каждая 1 заменяется на 0, пока не встретится 0; он заменяется на 1, и машина останавливается. Последовательность A01…1 (в конце t единиц) превращается в A10…0 — это прибавление единицы к двоичному числу. Если нулей нет совсем, слева допишется 1.

Шаг 2. Считаем. Пусть в конце t единиц перед нулём: A01…1 → A10…0. Нулей после: z(A) + t = 592, а было z(A) + 1 = 592 − t + 1. Это больше всего при t = 0 (последовательность оканчивается нулём): 592 + 1 = 593. Нужно, чтобы в A поместилось 592 нулей: 1200 − 1 ≥ 592 — выполняется.

Пример крайней ленты (сжато: «0×5» — пять нулей подряд, «(01)×3» — 010101): 0×592 1×607 0. После работы: 0×592 1×608.

Ответ: 593

Проверка на Python. Перебрать все ленты из тысячи символов нельзя, поэтому программа моделирует МТ и проверяет крайний случай из рассуждения: печатает число символов после работы и в исходной ленте.

L = 'λ'
prog = {
    ('q0', 'λ'): ('λ', 'L', 'q1'),
    ('q1', 'λ'): ('1', 'S', 'q1'),
    ('q1', '1'): ('0', 'L', 'q1'),
    ('q1', '0'): ('1', 'S', 'q1'),
}

def run(seq):
    tape = dict(enumerate(seq))
    pos, st = len(seq), 'q0'          # головка справа от последовательности
    while True:
        w, mv, st2 = prog[(st, tape.get(pos, L))]
        tape[pos] = w
        st = st2
        if mv == 'S':
            return ''.join(c for k, c in sorted(tape.items()) if c != L)
        pos += -1 if mv == 'L' else 1

# крайний случай из рассуждения
seq = '0' * 592 + '1' * 607 + '0' * 1
after = run(seq)
print(after.count('0'))       # должно быть 592
print(seq.count('0'))

Вариант 7

прореживание единиц · минимум

Исполнитель МТ — головка, которая движется вдоль бесконечной ленты из ячеек; в каждой ячейке записан ровно один символ алфавита, в том числе пустой символ λ. За один такт головка в состоянии q, обозревая символ в текущей ячейке, выполняет команду из таблицы: записывает символ, затем сдвигается влево (L), вправо (R), остаётся на месте (N) или останавливается (S), и переходит в новое состояние. Команда «1, L, q1» означает: записать 1, сдвинуться влево, перейти в состояние q1. В начальный момент головка находится в состоянии q0.

На ленте в соседних ячейках записана последовательность из 1000 символов, включающая только нули и единицы. Ячейки справа и слева от последовательности заполнены пустыми символами «λ». В начальный момент головка расположена в ближайшей ячейке справа от последовательности.

Программа работы исполнителя:

λ10
q0λ, L, q1
q1λ, S, q11, L, q20, L, q1
q2λ, S, q20, L, q10, L, q1

После выполнения программы на ленте осталось ровно 292 единицы. Определите минимально возможное число единиц в исходной последовательности.

Разбор

Шаг 1. Что делает программа. В состоянии q0 головка на пустой ячейке сдвигается влево — на последний символ последовательности. Состояние q2 означает «предыдущий (правее) символ — сохранённая единица». Если в q2 снова встречается 1, она стирается в 0. Поэтому в каждой группе подряд идущих единиц длины r, считая справа, единицы через одну заменяются нулями: остаётся ⌈r / 2⌉ единиц.

Шаг 2. Считаем. Группа из r единиц даёт ⌈r / 2⌉ ≥ 1 единиц, а одиночная единица остаётся сама. Значит, единиц после работы не больше, чем было, и минимум — когда все 292 единиц одиночные (разделены нулями): нужно 583 ≤ 1000 клеток.

Пример крайней ленты (сжато: «0×5» — пять нулей подряд, «(01)×3» — 010101): 0×417 (10)×291 1. После работы: 0×417 (10)×291 1.

Ответ: 292

Проверка на Python. Перебрать все ленты из тысячи символов нельзя, поэтому программа моделирует МТ и проверяет крайний случай из рассуждения: печатает число символов после работы и в исходной ленте.

L = 'λ'
prog = {
    ('q0', 'λ'): ('λ', 'L', 'q1'),
    ('q1', 'λ'): ('λ', 'S', 'q1'),
    ('q1', '0'): ('0', 'L', 'q1'),
    ('q1', '1'): ('1', 'L', 'q2'),
    ('q2', 'λ'): ('λ', 'S', 'q2'),
    ('q2', '0'): ('0', 'L', 'q1'),
    ('q2', '1'): ('0', 'L', 'q1'),
}

def run(seq):
    tape = dict(enumerate(seq))
    pos, st = len(seq), 'q0'          # головка справа от последовательности
    while True:
        w, mv, st2 = prog[(st, tape.get(pos, L))]
        tape[pos] = w
        st = st2
        if mv == 'S':
            return ''.join(c for k, c in sorted(tape.items()) if c != L)
        pos += -1 if mv == 'L' else 1

# крайний случай из рассуждения
seq = '0' * 417 + '10' * 291 + '1' * 1
after = run(seq)
print(after.count('1'))       # должно быть 292
print(seq.count('1'))

Вариант 8

пары «01» · максимум

Исполнитель МТ — головка, которая движется вдоль бесконечной ленты из ячеек; в каждой ячейке записан ровно один символ алфавита, в том числе пустой символ λ. За один такт головка в состоянии q, обозревая символ в текущей ячейке, выполняет команду из таблицы: записывает символ, затем сдвигается влево (L), вправо (R), остаётся на месте (N) или останавливается (S), и переходит в новое состояние. Команда «1, L, q1» означает: записать 1, сдвинуться влево, перейти в состояние q1. В начальный момент головка находится в состоянии q0.

На ленте в соседних ячейках записана последовательность из 800 символов, включающая только нули и единицы. Ячейки справа и слева от последовательности заполнены пустыми символами «λ». В начальный момент головка расположена в ближайшей ячейке справа от последовательности.

Программа работы исполнителя:

λ01
q0λ, L, q1
q1λ, S, q10, L, q11, L, q2
q2λ, S, q21, L, q11, L, q2

После выполнения программы на ленте осталось ровно 280 нулей. Определите максимально возможное число нулей в исходной последовательности.

Разбор

Шаг 1. Что делает программа. В состоянии q0 головка на пустой ячейке сдвигается влево — на последний символ последовательности. Состояние q2 означает «правее стоит единица». Если в q2 встречается 0, он заменяется на 1. Поэтому каждый 0, стоящий сразу слева от группы единиц (то есть каждая пара «01»), превращается в 1, а остальные символы не меняются.

Шаг 2. Считаем. Каждая пара «01» теряет нуль. Если пар r, то нулей было Z = 280 + r. Для r пар нужно r нулей и r единиц, а единиц всего 800 − Z, поэтому r ≤ 800 − (280 + r), то есть 2r ≤ 520, r ≤ 260. Наибольшее Z = 280 + 260 = 540.

Пример крайней ленты (сжато: «0×5» — пять нулей подряд, «(01)×3» — 010101): 0×281 (10)×259 1. После работы: 0×280 1×520.

Ответ: 540

Проверка на Python. Перебрать все ленты из тысячи символов нельзя, поэтому программа моделирует МТ и проверяет крайний случай из рассуждения: печатает число символов после работы и в исходной ленте.

L = 'λ'
prog = {
    ('q0', 'λ'): ('λ', 'L', 'q1'),
    ('q1', 'λ'): ('λ', 'S', 'q1'),
    ('q1', '0'): ('0', 'L', 'q1'),
    ('q1', '1'): ('1', 'L', 'q2'),
    ('q2', 'λ'): ('λ', 'S', 'q2'),
    ('q2', '1'): ('1', 'L', 'q2'),
    ('q2', '0'): ('1', 'L', 'q1'),
}

def run(seq):
    tape = dict(enumerate(seq))
    pos, st = len(seq), 'q0'          # головка справа от последовательности
    while True:
        w, mv, st2 = prog[(st, tape.get(pos, L))]
        tape[pos] = w
        st = st2
        if mv == 'S':
            return ''.join(c for k, c in sorted(tape.items()) if c != L)
        pos += -1 if mv == 'L' else 1

# крайний случай из рассуждения
seq = '0' * 281 + '10' * 259 + '1' * 1
after = run(seq)
print(after.count('0'))       # должно быть 280
print(seq.count('0'))

Вариант 9

инверсия через один · максимум

Исполнитель МТ — головка, которая движется вдоль бесконечной ленты из ячеек; в каждой ячейке записан ровно один символ алфавита, в том числе пустой символ λ. За один такт головка в состоянии q, обозревая символ в текущей ячейке, выполняет команду из таблицы: записывает символ, затем сдвигается влево (L), вправо (R), остаётся на месте (N) или останавливается (S), и переходит в новое состояние. Команда «1, L, q1» означает: записать 1, сдвинуться влево, перейти в состояние q1. В начальный момент головка находится в состоянии q0.

На ленте в соседних ячейках записана последовательность из 1500 символов, включающая только нули и единицы. Ячейки справа и слева от последовательности заполнены пустыми символами «λ». В начальный момент головка расположена в ближайшей ячейке справа от последовательности.

Программа работы исполнителя:

λ01
q0λ, L, q1
q1λ, S, q11, L, q20, L, q2
q2λ, S, q20, L, q11, L, q1

После выполнения программы на ленте осталось ровно 1024 нуля. Определите максимально возможное число нулей в исходной последовательности.

Разбор

Шаг 1. Что делает программа. В состоянии q0 головка на пустой ячейке сдвигается влево — на последний символ последовательности. Состояния q1 и q2 чередуются: в q1 символ инвертируется (0 ↔ 1), в q2 остаётся прежним. Значит, если нумеровать символы справа налево, меняются все символы на нечётных местах, а на чётных — остаются.

Шаг 2. Считаем. Пронумеруем символы справа налево. Нечётных мест 750, чётных 750. Пусть на нечётных местах было a нулей, на чётных — b. После работы нули на нечётных местах станут единицами и наоборот: нулей станет (750 − a) + b = 1024, то есть b = a + 274. Было нулей a + b = 2a + 274. Чтобы это было наибольшим, берём a как можно больше: a ≤ 750 и b = a + 274 ≤ 750, значит a = 476, b = 750. Ответ: 476 + 750 = 1226.

Пример крайней ленты (сжато: «0×5» — пять нулей подряд, «(01)×3» — 010101): (01)×274 0×952. После работы: 0×549 (10)×475 1.

Ответ: 1226

Проверка на Python. Перебрать все ленты из тысячи символов нельзя, поэтому программа моделирует МТ и проверяет крайний случай из рассуждения: печатает число символов после работы и в исходной ленте.

L = 'λ'
prog = {
    ('q0', 'λ'): ('λ', 'L', 'q1'),
    ('q1', 'λ'): ('λ', 'S', 'q1'),
    ('q1', '0'): ('1', 'L', 'q2'),
    ('q1', '1'): ('0', 'L', 'q2'),
    ('q2', 'λ'): ('λ', 'S', 'q2'),
    ('q2', '0'): ('0', 'L', 'q1'),
    ('q2', '1'): ('1', 'L', 'q1'),
}

def run(seq):
    tape = dict(enumerate(seq))
    pos, st = len(seq), 'q0'          # головка справа от последовательности
    while True:
        w, mv, st2 = prog[(st, tape.get(pos, L))]
        tape[pos] = w
        st = st2
        if mv == 'S':
            return ''.join(c for k, c in sorted(tape.items()) if c != L)
        pos += -1 if mv == 'L' else 1

# крайний случай из рассуждения
seq = '01' * 274 + '0' * 952
after = run(seq)
print(after.count('0'))       # должно быть 1024
print(seq.count('0'))

Вариант 10

вычитание единицы · максимум

Исполнитель МТ — головка, которая движется вдоль бесконечной ленты из ячеек; в каждой ячейке записан ровно один символ алфавита, в том числе пустой символ λ. За один такт головка в состоянии q, обозревая символ в текущей ячейке, выполняет команду из таблицы: записывает символ, затем сдвигается влево (L), вправо (R), остаётся на месте (N) или останавливается (S), и переходит в новое состояние. Команда «1, L, q1» означает: записать 1, сдвинуться влево, перейти в состояние q1. В начальный момент головка находится в состоянии q0.

На ленте в соседних ячейках записана последовательность из 1200 символов, включающая только нули и единицы. Ячейки справа и слева от последовательности заполнены пустыми символами «λ». В начальный момент головка расположена в ближайшей ячейке справа от последовательности.

Программа работы исполнителя:

λ10
q0λ, L, q1
q1λ, S, q10, S, q11, L, q1

После выполнения программы на ленте осталось ровно 200 нулей. Определите максимально возможное число нулей в исходной последовательности.

Разбор

Шаг 1. Что делает программа. В состоянии q0 головка на пустой ячейке сдвигается влево — на последний символ последовательности. Головка идёт влево от конца последовательности. Каждый 0 заменяется на 1, пока не встретится 1; эта единица заменяется на 0, и машина останавливается. Если записать последовательность как A10…0 (в конце t нулей), получится A01…1 — это вычитание единицы из двоичного числа.

Шаг 2. Считаем. Пусть в конце t нулей перед единицей: A10…0 → A01…1. Нули после работы — нули части A и ещё один (бывшая 1): z(A) + 1 = 200, значит z(A) = 199. Нулей было z(A) + t = 199 + t. Длина A равна 1200 − 1 − t и не меньше z(A), откуда t ≤ 1200 − 1 − 199 = 1000. Наибольшее число нулей: 199 + 1000 = 1199.

Пример крайней ленты (сжато: «0×5» — пять нулей подряд, «(01)×3» — 010101): 0×199 1 0×1000. После работы: 0×200 1×1000.

Ответ: 1199

Проверка на Python. Перебрать все ленты из тысячи символов нельзя, поэтому программа моделирует МТ и проверяет крайний случай из рассуждения: печатает число символов после работы и в исходной ленте.

L = 'λ'
prog = {
    ('q0', 'λ'): ('λ', 'L', 'q1'),
    ('q1', 'λ'): ('λ', 'S', 'q1'),
    ('q1', '1'): ('0', 'S', 'q1'),
    ('q1', '0'): ('1', 'L', 'q1'),
}

def run(seq):
    tape = dict(enumerate(seq))
    pos, st = len(seq), 'q0'          # головка справа от последовательности
    while True:
        w, mv, st2 = prog[(st, tape.get(pos, L))]
        tape[pos] = w
        st = st2
        if mv == 'S':
            return ''.join(c for k, c in sorted(tape.items()) if c != L)
        pos += -1 if mv == 'L' else 1

# крайний случай из рассуждения
seq = '0' * 199 + '1' * 1 + '0' * 1000
after = run(seq)
print(after.count('0'))       # должно быть 200
print(seq.count('0'))

Для самостоятельного решения

Варианты 11–15 без разборов. Ответ можно проверить кнопкой.

Вариант 11

инверсия через один · минимум

Исполнитель МТ — головка, которая движется вдоль бесконечной ленты из ячеек; в каждой ячейке записан ровно один символ алфавита, в том числе пустой символ λ. За один такт головка в состоянии q, обозревая символ в текущей ячейке, выполняет команду из таблицы: записывает символ, затем сдвигается влево (L), вправо (R), остаётся на месте (N) или останавливается (S), и переходит в новое состояние. Команда «1, L, q1» означает: записать 1, сдвинуться влево, перейти в состояние q1. В начальный момент головка находится в состоянии q0.

На ленте в соседних ячейках записана последовательность из 1000 символов, включающая только нули и единицы. Ячейки справа и слева от последовательности заполнены пустыми символами «λ». В начальный момент головка расположена в ближайшей ячейке справа от последовательности.

Программа работы исполнителя:

λ01
q0λ, L, q1
q1λ, S, q11, L, q20, L, q2
q2λ, S, q20, L, q11, L, q1

После выполнения программы на ленте осталось ровно 679 нулей. Определите минимально возможное число нулей в исходной последовательности.

Вариант 12

пары «01» · максимум

Исполнитель МТ — головка, которая движется вдоль бесконечной ленты из ячеек; в каждой ячейке записан ровно один символ алфавита, в том числе пустой символ λ. За один такт головка в состоянии q, обозревая символ в текущей ячейке, выполняет команду из таблицы: записывает символ, затем сдвигается влево (L), вправо (R), остаётся на месте (N) или останавливается (S), и переходит в новое состояние. Команда «1, L, q1» означает: записать 1, сдвинуться влево, перейти в состояние q1. В начальный момент головка находится в состоянии q0.

На ленте в соседних ячейках записана последовательность из 1500 символов, включающая только нули и единицы. Ячейки справа и слева от последовательности заполнены пустыми символами «λ». В начальный момент головка расположена в ближайшей ячейке справа от последовательности.

Программа работы исполнителя:

λ01
q0λ, L, q1
q1λ, S, q10, L, q11, L, q2
q2λ, S, q21, L, q11, L, q2

После выполнения программы на ленте осталось ровно 541 нуль. Определите максимально возможное число нулей в исходной последовательности.

Вариант 13

прореживание единиц · максимум

Исполнитель МТ — головка, которая движется вдоль бесконечной ленты из ячеек; в каждой ячейке записан ровно один символ алфавита, в том числе пустой символ λ. За один такт головка в состоянии q, обозревая символ в текущей ячейке, выполняет команду из таблицы: записывает символ, затем сдвигается влево (L), вправо (R), остаётся на месте (N) или останавливается (S), и переходит в новое состояние. Команда «1, L, q1» означает: записать 1, сдвинуться влево, перейти в состояние q1. В начальный момент головка находится в состоянии q0.

На ленте в соседних ячейках записана последовательность из 800 символов, включающая только нули и единицы. Ячейки справа и слева от последовательности заполнены пустыми символами «λ». В начальный момент головка расположена в ближайшей ячейке справа от последовательности.

Программа работы исполнителя:

λ10
q0λ, L, q1
q1λ, S, q11, L, q20, L, q1
q2λ, S, q20, L, q10, L, q1

После выполнения программы на ленте осталось ровно 380 единиц. Определите максимально возможное число единиц в исходной последовательности.

Вариант 14

прибавление единицы · максимум

Исполнитель МТ — головка, которая движется вдоль бесконечной ленты из ячеек; в каждой ячейке записан ровно один символ алфавита, в том числе пустой символ λ. За один такт головка в состоянии q, обозревая символ в текущей ячейке, выполняет команду из таблицы: записывает символ, затем сдвигается влево (L), вправо (R), остаётся на месте (N) или останавливается (S), и переходит в новое состояние. Команда «1, L, q1» означает: записать 1, сдвинуться влево, перейти в состояние q1. В начальный момент головка находится в состоянии q0.

На ленте в соседних ячейках записана последовательность из 1500 символов, включающая только нули и единицы. Ячейки справа и слева от последовательности заполнены пустыми символами «λ». В начальный момент головка расположена в ближайшей ячейке справа от последовательности.

Программа работы исполнителя:

λ01
q0λ, L, q1
q11, S, q11, S, q10, L, q1

После выполнения программы на ленте осталось ровно 537 нулей. Определите максимально возможное число нулей в исходной последовательности.

Вариант 15

инверсия через один · максимум

Исполнитель МТ — головка, которая движется вдоль бесконечной ленты из ячеек; в каждой ячейке записан ровно один символ алфавита, в том числе пустой символ λ. За один такт головка в состоянии q, обозревая символ в текущей ячейке, выполняет команду из таблицы: записывает символ, затем сдвигается влево (L), вправо (R), остаётся на месте (N) или останавливается (S), и переходит в новое состояние. Команда «1, L, q1» означает: записать 1, сдвинуться влево, перейти в состояние q1. В начальный момент головка находится в состоянии q0.

На ленте в соседних ячейках записана последовательность из 999 символов, включающая только нули и единицы. Ячейки справа и слева от последовательности заполнены пустыми символами «λ». В начальный момент головка расположена в ближайшей ячейке справа от последовательности.

Программа работы исполнителя:

λ10
q0λ, L, q1
q1λ, S, q10, L, q21, L, q2
q2λ, S, q21, L, q10, L, q1

После выполнения программы на ленте осталось ровно 580 нулей. Определите максимально возможное число нулей в исходной последовательности.