85 шагов для "калькулятора" (x→x+1, x→2x, x→3x)

Имеется калькулятор с тремя операциями.

Дано натуральное n. Сколько операций x→x+1, x→2x, x→3x нужно, чтобы из единицы построить n?

Задача: отыщите n: 1 ≤ n < 264 для получения которого необходимо 85 операций.

Пояснения

Исходная задача: Не получается решить задачу на программирование: калькулятор.

Последовательность A056796 на единицу больше количества операций этого калькулятора.

Ограничение n < 264 важно. Не так сложно взять большое n и получить большой ответ (n = 1068 требует 224 операции). Требуется найти не очень большое n с большим ответом.

84 операции для 18 446 744 025 449 496 575.

Новости

Ответ gord1402: 94 шага для 232320 - 1 (= 14 975 624 970 497 949 695). Это значительно лучше чем запрошенные 85. Это даже значительно больше чем моя оценка верхнего порога – 90.

95? Или 94 но для меньшего n?


Ответы (2 шт):

Автор решения: gord1402

Понятно что число с максимальным количеством операций будет максимально удалено от степеней 3-х и 2-х. В таком случае нам нужно лишь просмотреть числа 2**a * 3**b - 1, что сокращает количество чисел до ~64 * 40. Вот решение, что я написал:

import collections
import tqdm


def problem85(n):
    graph = {}
    queue = collections.deque()
    queue.append((n, 0))
    while queue:
        a, b = queue.popleft()
        if a not in graph:
            graph[a] = b
            if a == 1:
                break
            q, r = divmod(a, 3)
            if r == 0:
                queue.append((q, a))
            q, r = divmod(a, 2)
            if r == 0:
                queue.append((q, a))
            queue.append((a - 1, a))

    m = 1
    path = [m]
    while m != n:
        m = graph[m]
        path.append(m)
    return len(path) - 1

results = []

for pow2 in tqdm.tqdm(range(64)):
    for pow3 in range(40):
        if ((pow2 == 0 and pow3 == 0) or (2 ** pow2 * 3 ** pow3) > 2 ** 64): break
        result = problem85(2**pow2 * 3 ** pow3 - 1)
        if result > 60:
            results.append([result, pow2, pow3])

for result in sorted(results, key = lambda x:x[0]):
    print(result)

Где problem85 - функция решения оригинальной задачи.

Вот топ лист:

[87, 40, 15]
[88, 28, 21]
[88, 29, 20]
[88, 31, 18]
[88, 36, 17]
[89, 27, 23]
[89, 28, 22]
[89, 30, 19]
[89, 32, 18]
[89, 35, 17]
[89, 37, 17]
[90, 29, 21]
[90, 30, 20]
[90, 33, 18]
[90, 34, 18]
[91, 29, 22]
[91, 31, 19]
[92, 30, 21]
[92, 31, 20]
[92, 32, 19]
[92, 35, 18]
[93, 33, 19]
[94, 32, 20]
→ Ссылка
Автор решения: Stanislav Volodarskiy

Я воспользовался великолепной идеей из ответа gord1402. У меня уже была таблица рекордов (она есть на OEIS: https://oeis.org/A056817), полученная полным перебором. Для каждого числа операций я отыскал минимальное n требующее это количество операций. Например 143 строится за 10 операций, а все числа меньше требуют меньше операций.

Я попробовал к рекордам добавлять небольшие числа так, чтобы сумма делилась на много двоек и троек: 143 + 1 = 24·32.

Иногда деление не полное, остаётся небольшой множитель. Рекорд для 20 разлагается так:
12959 + 1 = 25·34·5.

Получилась таблица ниже. Она составлена неформально: сперва подбиралось небольшое t, потом проверялось что сумма "хорошо" разлагается. Но это всегда срабатывало: t принимает значения 0, 1, 2 и 5, а оставшийся после исключения двоек и троек множитель f1, 5 и 7.

fn n = 2a·3b·f - t fn n = 2a·3b·f - t
0 1 = 1 32 2799359 = 28·37·5 - 1
1 2 = 2 33 4478975 = 211·37 - 1
2 4 = 22 34 5598719 = 29·37·5 - 1
3 5 = 2·3 - 1 35 16796159 = 29·38·5 - 1
4 11 = 22·3 - 1 36 23514623 = 29·38·7 - 1
5 17 = 2·32 - 1 37 33592319 = 210·38·5 - 1
6 23 = 23·3 - 1 38 53747711 = 213·38 - 1
7 35 = 22·32 - 1 39 94058495 = 211·38·7 - 1
8 70 = 23·32 - 2 40 141087743 = 210·39·7 - 1
9 71 = 23·32 - 1 41 214990847 = 215·38 - 1
10 143 = 24·32 - 1 42 282175487 = 211·39·7 - 1
11 215 = 23·33 - 1 43 564350975 = 212·39·7 - 1
12 430 = 24·33 - 2 44 644972543 = 215·39 - 1
13 431 = 24·33 - 1 45 1128701951 = 213·39·7 - 1
14 863 = 25·33 - 1 46 1693052927 = 212·310·7 - 1
15 2158 = 24·33·5 - 2 47 2579890175 = 217·39 - 1
16 2159 = 24·33·5 - 1 48 3386105855 = 213·310·7 - 1
17 4319 = 25·33·5 - 1 49 6772211711 = 214·310·7 - 1
18 6479 = 24·34·5 - 1 50 10158317567 = 213·311·7 - 1
19 8639 = 26·33·5 - 1 51 13544423423 = 215·310·7 - 1
20 12959 = 25·34·5 - 1 52 20316635135 = 214·311·7 - 1
21 25918 = 26·34·5 - 2 53 40633270270 = 215·311·7 - 2
22 25919 = 26·34·5 - 1 54 40633270271 = 215·311·7 - 1
23 51839 = 27·34·5 - 1 55 81266540543 = 216·311·7 - 1
24 77759 = 26·35·5 - 1 56 121899810815 = 215·312·7 - 1
25 155518 = 27·35·5 - 2 57 162533081087 = 217·311·7 - 1
26 155519 = 27·35·5 - 1 58 243799621631 = 216·312·7 - 1
27 311039 = 28·35·5 - 1 59 487599243262 = 217·312·7 - 2
28 466559 = 27·36·5 - 1 60 487599243263 = 217·312·7 - 1
29 933118 = 28·36·5 - 2 61 1462797729787 = 217·313·7 - 5
30 933119 = 28·36·5 - 1 62 1462797729791 = 217·313·7 - 1
31 1866239 = 29·36·5 - 1 63 6269133127679 = 218·314·5 - 1

Дальше я повторил поиск gord1402 меняя параметры a, b, f, t. f менялся в диапазоне [1, 30] (брались только значения взаимно простые с 2 и 3), t – в диапазоне [0, 20]. Для 2a·3b·f - t рассчитывалось количество операций. Рекорды для 85, 94, 95:

85: n = 136496581762351103 = 224·319·7 - 1

94: n = 9827753886889279487 = 227·321·7 - 1

95: n = 13103671849185705983 = 229·320·7 - 1

Доказательства у меня нет, но я думаю что все рекорды имеют структуру замеченную gord1402. Если так, то 95 – самое большое число операций для n < 264.

→ Ссылка