Задача 2 треугольник информатика
Олимпиадная задача по информатике — Треугольные числа

Здравствуйте! Сегодня разберём олимпиадную задачу по информатике, которая называется треугольные числа.
Задача треугольные числа.
Школьник Никита этим летом отдыхал со своими родителями. Его любимым занятием на пляже было складывать из камешков правильные треугольники (правильным называется треугольник, у которого все стороны равны). Никита и не предполагал, что числа, из которых можно сложить правильный треугольник, называются треугольными. Вот несколько треугольных чисел: 1, 3, 6, 10, … .

Помогите Никите по заданному количеству камешков N найти наибольшую сторону правильного треугольника, который из них можно сложить. Например, если у Никиты 30 камешков, то длина наибольшей стороны правильного треугольника, который из них можно сложить, будет 7.

Тесты для самопроверки:
| 30 | 7 |
| 29 | 7 |
| 28 | 7 |
| 27 | 6 |
| 9876543210000 | 4444443 |
| 9223372036854775807 | 4294967295 |
Рассмотрим треугольные числа. Видим, что первое треугольное число — это просто 1. Второе число — это сумма чисел до 2 (1+2), третье число — сумма чисел до 3 (1+2+3) и т.д.

Плюс ко всему, второе число образует треугольник со стороной 2, третье число со стороной 3 и т.д.
Рассмотрим треугольное число по номером n. Видим, что это сумма арифметической прогрессии.

Свернём по формуле арифметической прогрессии. Число Sn (сумма арифметической прогрессии) в нашей задаче это количество камней, которое вводит пользователь. Число n в данном уравнении обозначает порядковый номер треугольного числа или длину стороны правильного треугольника, который можно составить из данного количества камней.
Остаётся решить данное уравнение относительно n в целых числах, чтобы разгадать нашу задачу.

Последние уравнение это и есть ответ в нашей задаче. Если n — будет дробным, значит мы должны его округлить в меньшую сторону, т.к. наше уравнение решается только в целых числах. (Дробное количество камней не может быть).
Запрограммируем данную задачу на C#
Т.к. число 9223372036854775807 * 8 превышает максимальное число даже для типа ulong, то будем использовать специальный тип BigInteger.
Для того, чтобы использовать BigInteger, нужно в ссылках добавить System.Numerics . И прописать using System.Numerics в программе.
Для этого типа данных не работает стандартная функция извлечения корня Math.Sqrt(), поэтому мы напишем свою функцию извлечения корня основанную на методе Ньютона. Эта функция извлекает корень и округляет результат в меньшую сторону. Об этом методе можете прочитать подробно в статье на этом сайте.
На этом всё, до свидания!
Определить возможность существования треугольника по сторонам
Задача
Треугольник существует только тогда, когда сумма любых двух его сторон больше третьей.
Дано: a , b , c – стороны предполагаемого треугольника.
Требуется сравнить длину каждого отрезка-стороны с суммой двух других. Если хотя бы в одном случае отрезок окажется больше суммы двух других, то треугольника с такими сторонами не существует.
Решение
Ниже приведены решения задачи на языке программирования Паскаль двумя способами. В первом случае все стороны проверяются в одном операторе if; во втором случае каждое условие проверяется отдельно, а программа содержит вложенные операторы if-else.
Программа 1 (предпочтительный способ решения):
В языке Паскаль логический оператор and имеет приоритет над операторам >, if проверяется, что каждая из сторон меньше суммы других. Если хотя бы одна будет больше, то все логическое выражение вернет ложь ( false ). В таком случае сработает ветка else .
В данном случае существование треугольника проверяется по-этапно. Если первое условие возвращает ложь, то программа переходит к последнему else. Если же первое условие соблюдено, то поток выполнения программы оказывается у вложенного if. Здесь проверяется уже второе условие. Если оно возвращает ложь, то программа переходит к предпоследнему else. Если и второе логическое выражение возвращает истину (true), то программа идет к третьему условию. При его соблюдении выполняется тело самого вложенного оператора if. При его несоблюдении сработает самое вложенное else.
Несмотря на то, что данная программа кажется длиннее, в определенных ситуациях она может выполняться быстрее, чем первая. Здесь если внешнее if возвращает ложь, то остальные логические выражения вообще не проверяются. В первой программе могут и проверяться (это зависит от особенностей языка программирования).
Задача 2 треугольник информатика
Откройте файл электронной таблицы, содержащей в каждой строке три натуральных числа.
Определите, сколько среди заданных троек чисел таких, которые могут быть сторонами прямоугольного треугольника.
Заметим, что треугольник является прямоугольным, если квадрат длины гипотенузы треугольника будет равен сумме квадратов длин катетов этого треугольника. Тогда в ячейке D1 запишем формулу =(МАКС(A1:C1))^2 и скопируем её во все ячейки диапазона D2:D5000. В ячейке E1 запишем формулу
и скопируем её во все ячейки диапазона E2:E5000. Таким образом, получим квадрат длины гипотенузы и сумму квадратов катетов для каждой тройки чисел. После этого в ячейку F1 запишем формулу =ЕСЛИ(D1=E1;1;0) и скопируем её во все ячейки диапазона F2:F5000. Теперь, воспользовавшись формулой =СУММ(F1:F5000), получим ответ — 2.
Отображение числа 9223372036854775807
Почему разные языки по-разному отображают число 9223372036854775807 , хотя все используют один и тот же формат 8-байтного double для представления чисел?
Здесь в каждой среде/языке два преобразования:
- Из константы в исходном коде в объект в памяти
- Печать этого объекта памяти выбранным способом.
Эффект от кода из вопроса для С++: volatile double x = 9223372036854775807.; схож с gcc’s -ffloat-store опцией и позволяет забыть о возможных дополнительных битах и думать только о 64-битных IEEE 754 числах двойной точности, используемые в рассматриваемой реализации (IEEE 754 не обязателен, но конкретная реализация для float чисел должна быть задокументирована).
Константа 9223372036854775807. из исходного кода превращается в 9223372036854775808. double (ожидаемо для этого типа, см. демонстрацию битового представления внизу). В CPython тоже самое происходит:
то есть 9223372036854775807. не может быть точно представлено в IEEE 754 double и поэтому используется приближение 9223372036854775808. (2 63 ), которое уже выводится точно в этом случае с помощью: cout << fixed << x; как ascii-строка: «9223372036854775808.000000» (в C локали).
Как double в памяти и в виде бит в IEEE 754 представлен, и как печать может происходить в С, подробно описано в ответе на вопрос printf как средство печати переменных в С.
В данном случае, так как число является степенью двойки, то легко найти его IEEE 754 представление:
d = ±знак · (1 + мантисса / 2 52 ) · 2 порядок − 1023
- знак овый бит равен нулю, так как число положительное
- порядок = (63 + 1023)10 = 100001111102, чтобы получить 2 63
- у мантисса все явные 52 бита нулевые (старший неявный 53ий бит всегда равен единице)
Все биты числа вместе:
Что подтверждается вычислениями на Питоне:
И в обратную сторону:
Порядок байт в памяти у числа в примере показан от старшего к младшему (big-endian), но фактически может быть и от младшего к старшему (little-endian):
Можно посмотреть, что не подряд идут представимые числа, вычитая/прибавляя по одному биту к мантиссе:
Разница в один бит для чисел этой величины ведёт к разнице больше тысячи в десятичном представлении: .. 4784 , .. 5808 , .. 7856 .
Результаты совпадают с предыдущими:
Javascript
Числа в JavaScript представлены интересным способом — целые как IEEE 754 double представлены. К примеру, максимальное число ( Number.MAX_SAFE_INTEGER ) равно 2 53 .
9223372036854775807 на три порядка больше MAX_SAFE_INTEGER поэтому нет гарантии, что n и n+1 представимы.
9223372036854776000 (результат document.write(9223372036854775807) в одной из javascript реализаций) допустим cтандартом в качестве строкового представления для 9223372036854775807 (это по-прежнему одно binary64 число: 0x1.0000000000000p+63 ).
Результаты побитовых операций вообще ограничены 32-битными числами со знаком. Можно посмотреть на какие ухищрения пришлость пойти, чтобы воспроизвести результат хэш-функции, реализованной в javascript: Как перевести из Javascript в Питон функцию хэширования строки.
В Java, double это тип со значениями, которые включают 64-bit IEEE 754 числа с плавающей точкой.
Возможная логика, почему 9223372036854776000 , а не 9223372036854775808. десятичное представление выбрано для binary64 числа 0x1.0000000000000p+63 в том, что в общем случае это позволяет меньше цифр печатать для дробных чисел — не отображаются завершающие нули (это спекуляция — я не углублялся в этот вопрос).
msdn утверждает что double в C# соотвествует IEEE 754.
9223372036854780000.0 намекает, что Console.WriteLine(«<0:0.0>«, x); округляет до 15 цифр при печати. Напечатанное число отличается от x :
Вероятно это происходит по cхожей причине, что и 0.1 показывается как 0.1 при печати, а не 0.10000000000000001 или вообще 0.1000000000000000055511151231257827021181583404541015625 ( 0.1 .hex() == ‘0x1.999999999999ap-4’ ). Более того binary64 представление другое (2 63 vs. 2 63 +2 12 ) (единственный из представленных примеров в вопросе, который по умолчанию не выводит эквивалентное представление).
Возможно, приоритет в округлении до 15 цифр, не обращая внимание достаточно ли это, чтобы эквивалентное binary64 представление получить. Не только C# себя так ведёт, к примеру, numpy.array в Питоне выводит по умолчанию 8 цифр:
Показ 17 цифр в C# возможен с помощью стандартного «<0:R>» формата, что выводит 9.2233720368547758E+18 , то есть снова ту же рассматриваемую изначальную 2 63 степень получили:
Последовательные числа, представимые в формате IEEE 754 double , в окрестности 9223372036854775807 это
Ближайшим является 9223372036854775808 .
А разница в выводе возникает только на этапе формирования десятичного представления двоичного плавающего IEEE 754 числа. Внутренне все вышеупомянутые реализации языков используют IEEE 754 double , значение которого во всех случаях равно именно 9223372036854775808 , в чем легко убедиться путем вычитания из хранимого числа его старших разрядов.
Например в вашем C# примере достаточно вместо x напечатать x — 9223000000000000000 , как «недостающие» младшие разряды сразу «проявятся»: http://ideone.com/H5eKPe
Абсолютно то же самое происходит и в Javascript.
Это задача с разряда, почему 0.1 + 0.1 не всегда точно 0.2. Если посмотреть в википедию, то станет понятно, что числа двойной точности имеют мантису в 52 бита. 52 бита дают 15-16 цифр. А у Вас их больше.
UPD
Нашел чудный сервис для просмотра чисел двойной точности http://www.binaryconvert.com/convert_double.html
Вбиваем в него 9223372036854775807 и 9223372036854775808, и даже 9223372036854775809 и видим, что у них всех одно и тоже бинарное представление — 0x43E0000000000000. Обратное преобразование для него дает 9.223372036854775808E18 . То есть, данный формат не может различить три заданных числа. Это отвечает на первую часть вопроса.
Почему же разные языки по разному отображают это число? Во первых, каждый из языков использует какую то свою дефолтно настроенную систему для форматирования вывода. А что именно ели/пили разработчики языка/компилятора/платформы в этот момент, мы не знаем. Во вторых, каждый разработчик пытается сделать свой, единственно верный и правильный парсер-преобразователь.
Посмотрим на вывод java и пропустим его через конвертор 9223372036854776000 => 0x43E0000000000000 — видим то же самое представление. Видимо алгоритм java другой. Его видимо использует и javascript (с ним правда не все очевидно — есть много различных реализаций, но все проверенные мной варианты на видне/линуксе давали один и тот же результат).
А вот у шарпа тут похоже бага: 9223372036854780000 => 0x43E0000000000002 (двойка в конце). Но потом они видимо исправились и ввели специальный вид форматирования — round trip format
и в этом случае имеем 9.2233720368547758E+18, что эквивалентно 9223372036854775800. В бинарном представлении это будет все тот же 0x43E0000000000000. Заставить вывести сразу в правильной форме не получилось 🙁
Вывод. Все, кроме шарпа вывели правильно. Абсолютно правильно. Просто, по историческим (и видимо патентным/велосипедным правилам) используют разные алгоритмы предобразования. Шарп выделился, но думаю, что на то есть исторические причины (вплоть до оптимизации по скорости или просто человеческая ошибка).
Длинная арифметика от Microsoft
Известно, что компьютер может оперировать числами, количество бит которых ограниченно. Как правило, мы привыкли работать с 32-х и 64-х разрядными целыми числами, которым на платформе .NET соответствуют типы Int32 (int) и Int64 (long) соответственно.
А что делать, если надо представить число, такое как, например, 29! = 8841761993739701954543616000000? Такое число не поместится ни в 64-х разрядный, ни тем более 32-х разрядный тип данных. Именно для работы с такими большими числами существует длинная арифметика.
Длинная арифметика — в вычислительной технике операции (сложение, умножение, вычитание, деление, возведение в степень и т.д.) над числами, разрядность которых превышает длину машинного слова данной вычислительной машины. Эти операции реализуются не аппаратно, а программно, используя базовые аппаратные средства работы с числами меньших порядков.
Длинную арифметику также можно считать одним из разделов олимпиадного программирования, поскольку очень часто при решении задач, разрядности стандартных типов не хватает для представления конечного результата. При выборе языка программирования для олимпиадных нужд не маловажным является встроенный в него набор средств (готовых библиотек, реализованных классов). Многие языки (Java, Ruby, Python) имеют встроенную поддержку длинной арифметики, что в разы может сократить время написания программы.
Платформа .NET вплоть до 4.0 версии не имела встроенной поддержки работы с длинными числами. В 4-той же версии .NET обзавелась не только длинными, но и комплексными числами. Этот функционал доступен через сборку System.Numerics и типы BigInteger и Complex определенные в одноимённом с названием сборки пространстве имён.
Следует сказать, что структура BigInteger должна была появиться ещё в .NET 3.5, однако на тот момент она не была полностью готова, её реализация не отвечала всем потребностям (сюда можно отнести и проблемы производительности), поэтому было принято решение отложить её выход до .NET 4.0.
В данной статье я бы хотел рассмотреть подробности реализации длинной арифметики от Microsoft.
Общие понятия
Идея представления длинных чисел в памяти компьютера достаточно проста. Рассмотрим число 123456789 в десятеричной системе счисления. Очевидно, его можно представить следующим образом:
12345678910 = 1*10 8 + 2*10 7 + 3*10 6 + 4*10 5 + 5*10 4 + 6*10 3 + 7*10 2 + 8*10 1 + 9*10 0
В общем случае, любое число можно представить в виде:
A = an-1β n-1 + an-2β n-2 +…+a1β + a0
где β – основание системы счисления, в которой мы представляем число, а коэффициенты ai удовлетворяют двойному неравенству 0 ≤ ai < β.
Представление числа напоминает представление многочлена, только вместо x в соответствующей степени имеем основание β в нужной степени. Как известно, многочлен a0 + a1x + a2x 2 + … + anx n удобно представлять в виде массива, элементы которого представляют коэффициенты ai, а индекс i — определяет соответствующую степень x. Длинное число хранится аналогично, осталось определиться с выбором основания β.
Например, то же самое число 123456789 можно представить в десятитысячной (β = 10 4 ) системе счисления следующим образом:
12345678910 = 1*(10 4 ) 2 + 2345*(10 4 ) 1 + 6789*(10 4 ) 0
Представляя число 123456789 в десятитысячной системе счисления, мы получаем сразу два преимущества: во-первых, сокращаем количество потребляемой памяти, так как вместо массива из 9 чисел нам достаточно хранить массив из 3 чисел (1, 2345 и 6789), во-вторых, значительно уменьшаем время выполнения стандартных операций над длинными числами, поскольку за раз обрабатываем 4 разряда числа. В общем, компьютер одинаково быстро складывает одноразрядные и 32-разрядные числа, поэтому этим следует воспользоваться.
Основание системы счисления β обычно зависит от максимального размера базового типа данных на компьютере, и выбирается, исходя из следующих соображений:
- основание должно подходить под один из базовых типов данных;
- основание должно быть как можно больше, чтобы уменьшить размер представления длинного числа и увеличить скорость операций с ними, но достаточно малого размера, чтобы все операции с коэффициентами использовали базовый тип данных;
- для удобства вывода и отладки можно выбрать β как степень 10, β — степень двойки позволяет проводить быстрые операции на низком уровне.
BigInteger от Microsoft
Если посмотреть на структуру BigInteger через декомпилятор Reflector или dotPeek, то увидим следующие поля:
Структура содержит всего два экземплярных поля (_sign и _bits), остальные поля представляют собой константы и статические поля для чтения представляющие значения структуры для чисел -1, 0 и 1.
Можно предположить, что в переменной _sign хранится знак числа, а массив _bits содержит коэффициенты ai. Учитывая, что массив _bits имеет тип uint[], можно так же предположить, что в качестве основания β взята степень двойки 2 32 (поскольку uint — 32 разрядное беззнаковое число).
Итак, попробуем подтвердить или опровергнуть наши предположения.
Конструктор, принимающий int, в качестве аргумента выглядит так:
Его реализация может рассказать немного больше о назначении переменной _sign. Как видно, если длинное число помещается в int диапазон (от -2 31 до 2 31 -1), то оно хранится в переменной _sign, а массив _bits при этом не используется, он равен null. Эта оптимизация, должна ускорить работу типа BigInteger, а так же снизить размер потребляемой памяти когда число на самом деле не является большим.
Конструктор, принимающий uint в качестве аргумента, выглядит следующим образом:
В зависимости от того помещается ли число в int диапазон, оно записывается либо в переменную _sign, либо в массив _bits.
Следующий конструктор, принимающий 64-х разрядное число со знаком (long) поможет ответить на вопрос о выборе основания системы счисления:
Если число не помещается в int диапазон, то, как мы видим переменная _sign содержит знак числа (-1 – для отрицательного и 1 – для положительного), а массив _bits содержит те самые коэффициенты ai и заполняется следующим образом:
В данном случае 64-х разрядное число num разбивается на два 32-х разрядных: (uint)num и (uint)(num >> 32). Первое число представляет собой последние 32 бита числа num, в то время как второе первые 32 бита (смещение вправо на n бит равносильно целочисленному делению на 2 n ).
Давайте определим, как будет храниться число long.MaxValue = 2 63 -1 = 9223372036854775807 в структуре BigInteger. Для этого поделим его на 2 32 :
Фактически (uint)long.MaxValue = 4294967295, (uint)(long.MaxValue >> 32) = 2147483647.
Значит, 9223372036854775807 = 2147483647*(2 32 ) 1 + 4294967295*(2 32 ) 0 , и BigInteger
будет представлен парой:
_sign = 1
_bits = <4294967295, 2147483647>// вспоминаем, что число храниться задом наперёд
Для длинного числа -1234567891011121314151617181920 имеем:

То есть число раскладывается по степеням 2 32 следующим образом:
1234567891011121314151617181920 = 15*(2 32 ) 3 + 2501550035*(2 32 ) 2 + 3243814879*(2 32 ) 1 + 4035623136*(2 32 ) 0
Значит, BigInteger будет представлен парой:
_sign = -1 // знак числа
_bits =
Число, помещающееся в int диапазон, скажем, 17 будет храниться следующим образом:
_sign = 17
_bits = null
Исследовав конструкторы структуры BigInteger можно заключить:
- если число помещается в int диапазон, то оно хранится в переменной _sign;
- если число не помещается в int диапазон, то его знак хранится в переменной _sign (-1 – для отрицательного и 1 – для положительного), а массив _bits содержит коэффициенты ai разложения длинного числа с основанием 2 32 .
В общем, структура BigInteger является полноценной реализацией длинной арифметики на платформе .NET. При этом Microsoft постаралась максимально близко приблизить её к примитивным числовым типам: экземпляр BigInteger можно использовать точно так же, как и любой другой целочисленный тип. BigInteger перегружает стандартные числовые операторы для выполнения основных математических операций, таких как сложение, вычитание, деление, умножение, вычитания, отрицание и унарное отрицание. Можно также использовать стандартные числовые операторы для сравнения двух значений BigInteger друг с другом. Как и другие типы целого числа, BigInteger поддерживает битовые операторы And, Or, XOR, сдвиг влево и сдвиг вправо.
Для языков, не поддерживающих пользовательские операторы, структура BigInteger также предоставляет эквивалентные методы для выполнения математических операций. Это относится к методам Add, Divide, Multiply, Negate, Subtract и некоторым другим. Точно так же Microsoft поступило в реализации структуры Decimal.
Многие члены структуры BigInteger напрямую соответствуют членам других целых типов. Кроме того, BigInteger добавляет такие элементы как:
- IsEven – определяет является ли число чётным;
- IsPowerOfTwo — определяет является ли число степенью двойки;
- Sign — возвращает значение, указывающее знак числа BigInteger;
- Abs — возвращает абсолютное значение числа BigInteger;
- DivRem — возвращает частное и остаток от операции деления;
- GreatestCommonDivisor — возвращает наибольший общий делитель для двух чисел;
- Log — возвращает логарифм указанного числа в системе счисления с указанным основанием;
- Max / Min — возвращает наибольшее / наименьшее из двух чисел;
- ModPow — выполняет модульное деление числа, возведенного в степень другого числа;
- Pow — возводит значение BigInteger в заданную степень.
Пару слов о BigInteger в Mono и Java
Следует отметить, что Mono так же обладает поддержкой длинной арифметики. Реализация структуры BigInteger в Mono практически ничем не отличается от реализации Microsoft, кроме как, того что в ней нет оптимизации для чисел представимых типом int.
То есть число 17 в Mono будет представлено парой:
_sign = 1 // знак числа
_bits =
Аналогичная реализация BigInteger представлена в Java:
Поскольку в Java отсутствуют беззнаковые типы, то массив mag имеет тип int[]. Соответственно представления длинного числа в Java и .NET будут отличаться. В .NET представление будет немного эффективнее, поскольку тип uint охватывает больший диапазон:
В Java, так же как и в Mono нет оптимизации для чисел, представимых типом int.
Производительность BigInteger
Работая с длинным числом BigInteger, необходимо помнить о возможных проблемах связанных с производительностью. Например, казалось бы, безобидный оператор ++ может оказать существенное влияние на производительность:
Хотя, кажется, что в этом примере происходит изменение значения существующего объекта, это не так. Объекты BigInteger неизменяемы, то есть внутренне, общеязыковая среда выполнения фактически создает новый объект BigInteger и присваивает ему значение на единицу больше предыдущего.
В данном примере, можно поступить следующим образом: выполнить промежуточные операции, используя обычные числовые типы, а затем использовать BigInteger:
Другие числовые типы .NET Framework также являются неизменяемыми. Однако поскольку тип BigInteger не имеет верхней или нижней границы, его значения могут расти до очень больших значений и иметь измеримое влияние на производительность.
Вместо заключения
Подводя итог, можно сказать, что платформа .NET, начиная с 4 версии, обзавелась полноценной реализацией целочисленной длинной арифметики. Возможно, для полного счастья осталось реализовать структуру BigRational, которая уже достаточно давно присутствует в статусе бета в .NET BCL.
Описание структуры BigRational: структура BigRational основывается на типе BigInteger, который был представлен в .NET Framework 4 и позволяет создавать рациональные числа произвольной точности. Рациональное число представляет собой отношение двух целых чисел, и в этой реализации структуры BigRational в качестве делимого (числителя) и делителя (знаменателя) используется тип BigInteger.
Олимпиадная задача по информатике — Треугольные числа

Здравствуйте! Сегодня разберём олимпиадную задачу по информатике, которая называется треугольные числа.
Задача треугольные числа.
Школьник Никита этим летом отдыхал со своими родителями. Его любимым занятием на пляже было складывать из камешков правильные треугольники (правильным называется треугольник, у которого все стороны равны). Никита и не предполагал, что числа, из которых можно сложить правильный треугольник, называются треугольными. Вот несколько треугольных чисел: 1, 3, 6, 10, … .
Помогите Никите по заданному количеству камешков N найти наибольшую сторону правильного треугольника, который из них можно сложить. Например, если у Никиты 30 камешков, то длина наибольшей стороны правильного треугольника, который из них можно сложить, будет 7.
Тесты для самопроверки:
| 30 | 7 |
| 29 | 7 |
| 28 | 7 |
| 27 | 6 |
| 9876543210000 | 4444443 |
| 9223372036854775807 | 4294967295 |
Рассмотрим треугольные числа. Видим, что первое треугольное число — это просто 1. Второе число — это сумма чисел до 2 (1+2), третье число — сумма чисел до 3 (1+2+3) и т.д.
Плюс ко всему, второе число образует треугольник со стороной 2, третье число со стороной 3 и т.д.
Рассмотрим треугольное число по номером n. Видим, что это сумма арифметической прогрессии.
Свернём по формуле арифметической прогрессии. Число Sn (сумма арифметической прогрессии) в нашей задаче это количество камней, которое вводит пользователь. Число n в данном уравнении обозначает порядковый номер треугольного числа или длину стороны правильного треугольника, который можно составить из данного количества камней.
Остаётся решить данное уравнение относительно n в целых числах, чтобы разгадать нашу задачу.

Последние уравнение это и есть ответ в нашей задаче. Если n — будет дробным, значит мы должны его округлить в меньшую сторону, т.к. наше уравнение решается только в целых числах. (Дробное количество камней не может быть).
Запрограммируем данную задачу на C#
Т.к. число 9223372036854775807 * 8 превышает максимальное число даже для типа ulong, то будем использовать специальный тип BigInteger.