Как решать задачи ресурса "проект Эйлер"? Георгий Гуляев 3 июля 2026 г. На сайте https://projecteuler.net опубликовано на данный момент более 1000 задач и эта коллекция со временем продолжает пополнять- ся. Придумывают эти задачи математики со знаниями в области про- граммирования. В большинстве своем это задачи из теории чисел или комбинаторики, но встречаются и другие темы. Каждая задача имеет сложность в процентах от 0 до 40, в зависимо- сти от того как быстро ее решают пользователи ресурса. Решение, как правило, требует написания некоторого небольшого кода на каком-либо языке программирования, но для более сложных задач одного програм- мирования бывает недостаточно - требуются знания и умения в области математики. Решив задачу (введя правильный численный ответ), пользователь полу- чает доступ к закрытым материалам задачи и решениям других поль- зователей, а также может опубликовать свое решение. Авторы ресурса, естественно, не хотели бы, чтобы решения задач и ответы к ним публи- ковались где-либо еще. Разрешено только в целях обучения обсуждать идеи решения первых 100 задач. Поэтому, в данной статье для демонстрации поиска решения задач такого рода, мы не будем использовать задачи ресурса https://projecteuler. net , а рассмотрим свою оригинальную задачу. 1 Задача . На плоскости расположена прямоугольная таблица, в клетках которой записаны все натуральные числа снизу вверх по диагоналям в следующим порядке: Определим функцию f ( x, y ) = числу в столбце x и строке y таблицы, тогда f (1 , 1) = 1 , f (2 , 1) = 2 , f (1 , 2) = 3 , f (2 , 2) = 5 , f (5 , 3) = 24 , ... . 1. Вычислить f (123456789 , 987654321) . 2. Определим функцию s ( n ) = n X x =1 n X y =1 ( f ( x, y ) − xy ) Можно проверить, что s (123) = 75367635 , s (123456) = 77432320610578913280 . Вычислить s (1234567890) . В качестве ответа использовать 10 последних цифр результата вычисления. Решение . 1. Первое задание - относительно простое. Тут присутствуют чисто тех- нические сложности при написании функции f ( x, y ) . Если не применять никакой математики, то можно просто строить всю таблицу ( x, y ) до некоторого значения n и затем использовать ее для вычисления f ( x, y ) . Программа на языке программирования Julia: function table(n) l = [(1,1)] for i in 2:n (x,y) = l[end] if x==1 x=y+1 y=1 push!(l,(x,y)) else x-=1 y+=1 push!(l,(x,y)) end end l end julia> l = table(28) 28-element Vector{Tuple{Int64, Int64}}: (1, 1) (2, 1) (1, 2) (3, 1) (2, 2) (1, 3) (4, 1) (3, 2) (2, 3) (1, 4) (5, 1) (4, 2) (3, 3) (2, 4) (1, 5) (6, 1) (5, 2) (4, 3) (3, 4) (2, 5) (1, 6) (7, 1) (6, 2) (5, 3) (4, 4) (3, 5) (2, 6) (1, 7) julia> l[25] (4, 4) Тут мы вывели все координаты ( x, y ) для чисел от 1 до 28, например для 25 это (4 , 4) . Лучше, конечно, не строить таблицу в памяти, так как для больших n она будет занимать много места, а только пробегать по ней. Так появляется наша первая версия для функции f ( x, y ) : function f(x,y) i = 1; j = 1; r = 1 while i<x+y&&j<x+y if i==x&&j==y return r end if i==1 i=j+1 j=1 else i-=1 j+=1 end r+=1 end end julia> f(3,4) 19 julia> f(4,4) 25 Координаты ( x, y ) всегда попадают в квадрат со стороной менее x + y , поэтому действуют ограничения: i < x + y и j < x + y . Эта програм- ма очень неэффективная, с ее помощью решить первую задачу мы не сможем: julia> @time f(12345,54321) 2.457699 seconds 2222132101 f (123456 , 654321) - уже дождаться невозможно. Пришло время математики. Придется немного порассуждать, чтобы вы- вести общую формулу для f ( x, y ) . В таблице на картинке в условии зада- чи возьмем какое-нибудь число в первом ряду, например 16. Количество чисел до него можно вычислить как сумму 1 + 2 + 3 + 4 + 5 = 15. Это сумма арифметической прогрессии: 5(5+1) 2 , таким образом 16 = 5(5+1) 2 + 1 или 16 = 6(6 − 1) 2 + 1 , учитывая, что 16 - шестое число в первом ряду. В общем случае f ( x, 1) = x ( x − 1) 2 + 1 . Теперь, для того чтобы получить формулу для f ( x, y ) , рассмотрим частный случай: f(x+y-1,1) = (x+y-1)(x+y-2) 2 + 1 По построению таблицы, при b < a у нас справедлива формула f ( a, b ) = f ( a − 1 , b + 1) + 1 . Применяя ее y − 1 раз к формуле для f ( x + y − 1 , 1) , получаем f(x,y) = (x+y-1)(x+y-2) 2 + y Теперь мы можем решить первую задачу без проблем: f(x,y) = div((x+y-1)*(x+y-2),2) + y julia> @time f(123456789,987654321) 0.000000 seconds 617283948703703707 2. Теперь, когда у нас есть такая простая формула, кажется, что и со вто- рой частью задачи у нас не будет проблем, но не тут то было. Функцию для вычисления суммы составить несложно: function sm(n) f(x,y) = div((x+y-1)*(x+y-2),2) + y s = Int128(0) for i in 1:n, j in 1:n s+=f(i,j)-i*j end s end Здесь мы накапливаем сумму в переменной типа Int128, так как при больших n она может превзойти Int64. julia> sm(123) 75367635 julia> sm(12345) 7740880282734900 julia> @time sm(123456) 26.305627 seconds 77432320610578913280 Результаты вычисления sm (123) и sm (123456) совпали с приведенными в условии задачи, однако становится очевидным, что эта функция так- же недостаточно эффективна и не позволит нам за приемлемое время вычислить требуемое значение: sm (1234567890) . Опять обратимся к математике. Если существует возможность вычис- лить требуемую сумму быстрее, чем полный перебор всех слагаемых, то должно быть какое-то соотношение (формула, теорема), позволяющее вычислять такие суммы. Прежде всего, заметим, что найденную формулу для f ( x, y ) можно немно- го видоизменить, раскрывая скобки: f ( x, y ) = ( x + y − 1)( x + y − 2) 2 + y = ( x + y − 1)( x + y ) − 2( x + y − 1)) 2 + y = ( x + y )( x + y − 1)) 2 − x + 1 то есть f(x,y) = (x+y)(x+y-1) 2 − x + 1 Обратим внимание на то, что в формуле присутствуют так называе- мые треугольные числа вида: T n = n ( n − 1) 2 . Поиском в интернет нахо- дим следующие соотношения для них (смотри, например, статью из ви- кипедии https://ru.wikipedia.org/wiki/%D0%A2%D1%80%D0%B5%D1%83% D0%B3%D0%BE%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D1%87%D0%B8%D1%81%D0% BB%D0%BE ): T n + m = T n + T m + mn T 1 + T 2 + T 3 + ... + T n = 0 + 1 + 3 + 6 + ... + n ( n − 1) 2 = n 3 − n 6 Таким образом, на основании первого равенства, формулу для f ( x, y ) можно переписать в виде: f ( x, y ) = ( x + y )( x + y − 1) 2 − x + 1 = T x + y − x + 1 = T x + T y + xy − x + 1 Применяя теперь эту формулу для f ( x, y ) и второе равенство, получаем s ( n ) = n X x =1 n X y =1 ( f ( x, y ) − xy ) = n X x =1 n X y =1 ( T x + T y − x +1) = n X x =1 ( nT x + n 3 − n 6 − nx + n ) = n n 3 − n 6 + n n 3 − n 6 − n n ( n + 1) 2 + n 2 = 2 n ( n 3 − n ) − 3 n 2 ( n + 1) + 6 n 2 6 = 2 n 4 − 2 n 2 − 3 n 3 − 3 n 2 + 6 n 2 6 = n 2 (2 n 2 − 3 n + 1) 6 = n 2 (2 n − 1)( n − 1) 6 Таким образом, сумму s ( n ) можно вычислять, даже не зная всех ее сла- гаемых. Теперь, без проблем мгновенно получается требуемый результат: sm(n) = div(n^2*(2*n-1)*(n-1),6) julia> sm(123) 75367635 julia> sm(Int128(123456)) 77432320610578913280 julia> sm(Int128(1234567890)) 774352408386692628193094876226110850 Последние 10 цифр: 6226110850 Выводы . Для решения подобных задач бывает недостаточно умения просто программировать на каком-либо языке. Поиск эффективного ал- горитма может потребовать от вас некоторых знаний в области матема- тики и определенной математической культуры для проведения логиче- ских рассуждений и преобразований математических выражений.
Как решать задачи ресурса "проект Эйлер"?
На примере решения своей задачи продемонстрирована общая идея решения задач на ресурсе "проект Эйлер" (projecteuler.net).
The general idea of solving problems on the Project Euler resource (projecteuler.net) is demonstrated using one example own problem.
Для решения подобных задач бывает недостаточно умения просто программировать на каком-либо языке. Поиск эффективного ал- горитма может потребовать от вас некоторых знаний в области матема- тики и определенной математической культуры для проведения логиче- ских рассуждений и преобразований математических выражений.