Решить задачу на python,оптимизировать

n = int(input())
total_sum = n * (n + 1) // 2
count = 0

# Перебираем все возможные позиции начала и конца.
for i in range(1, n + 1):
   for j in range(i, n + 1):
    removed_sum = (j * (j + 1)) // 2 - ((i - 1) * i) // 2
    
    if total_sum - removed_sum == removed_sum:
        count += 1

print(count)

введите сюда описание изображения

Задача E. Erasing numbers
Входной файл: Стандартный вход
Ограничение времени: 1 сек
Выходной файл: Стандартный выход
Ограничение памяти: 256 Мб
Условие
В Научно-исследовательском институте, где работает Тимофей, продолжается успешное исследование ряда натуральных чисел. Каждый день его коллеги открывают всё новые и новые свойства этой последовательности, и Тимофей старается от них не отставать. Сегодня Тимофей, как обычно, выписал на доске в ряд натуральные числа от 1 до и пытается ответить на вопрос, возможно ли стереть в середине списка несколько (не менее одного) чисел, идущих подряд, чтобы сумма оставшихся чисел слева равнялась сумме оставшихся чисел справа? Формат входных данных Единственная строка входных данных содержит натуральное число . Формат выходных данных Выведите в первой строке неотрицательное целое число — количество различных способов стереть числа.
Ограничения
3 ≤ n ≤ 10^5

Пояснения к примерам.

В первом примере дано . Перечислим все способы стереть числа в середине ряда:

1 # 3 4 5
1 2 # 4 5
1 2 3 # 5
1 # # 4 5
1 2 # # 5
1 # # # 5

Ни в одном из них нужное свойство не достигается. Во втором примере дано . Перечислим все хорошие способы стереть числа в середине ряда:

1 2 3 4 5 6 # # # ## ## ## ## ## ## ## ## ## ## ## 21
1 2 3 4 5 6 7 8 9 10 11 12 ## ## ## ## ## 18 19 20 21

В первом списке сумма чисел слева и справа равны 21, во втором — 78. Всего два способа.


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

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

Тут явно напрашивается одна из типовых методик для решения алгоритмических задач - "метод двух указателей".

  • Делаем два указателя - на начало списка и на конец списка
  • Идём по условиям (см. ниже) с начала списка вперёд первым указателем и с конца к началу вторым указателем
  • Попутно аккумулируем две суммы - от начала списка до первого указателя и от второго указателя до конца списка
  • В зависимости от того, равны суммы или какая-то из них больше, либо увеличиваем список найденных вариантов, либо сдвигаем тот указатель, чья сумма меньше
  • Когда указатели встретятся, выводим результат

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

Можно вспомнить ещё формулы для суммы чисел ряда, возможно они тоже дадут какую-то оптимизацию, но это нужно ещё подумать. Возможно, это позволит сдвигать левый указатель сразу на вычисленную позицию, пересчитав её из разницы сумм и текущего числа под левым указателем.

Код сами напишите, он совсем не сложный, тут главное алгоритм придумать.

→ Ссылка