Статья Автор: Лебедев Дмитрий

(КЕГЭ27-2021) Продолжение разбора задания F27-01 (Оптимизация и эффективное решение)

Продолжим рассмотрение решения задания F27-01 (начало здесь)
Мы остановились на решении (это уже исправленная версия)
Исправления коснулись последней строчки и обусловлены:
  • yyy +1, так как искали минимальную длину отрезка (j - i), а надо количество элементов(точек), то есть j - i + 1
  • zzz + 1, в последовательности нумерация с 1, а в списке с 1


Начнем ОПТИМИЗАЦИЮ решения
Вначале "уберем" использование словаря D,. Для этого по "ходу" будем обновлять счетчики и  хранить индексы "лучшей" пары 
(для удобства скроем блок ВВОДА и уберем старые комментарии)


Явно есть улучшение  по расходу памяти (словарь мог состоять из порядка nзаписей), но "читаемось" кода "пострадала"
Можно попробовать запустить этот код на файле "А27-01_002" (файл В), но выполнение программы потребует очень много времени.
Нетрудно заметить проблему, которая "сильно тормозит" процесс - это восьмая строка с оператором k = sum(A[i : j+1])  
Опытный пользователь сказажет "надо использовать префиксные суммы"
Поясним, о чем речь 
\(S_i^j\ =\ A_i\ +\dots\ A_j =\ A_i\ +\dots\ A_j +( A_1+\dots+A_{i-1}) - ( A_1+\dots+A_{i-1}) = \\=(A_1+\dots+A_{i-1})\ +\ A_i\ +\dots\ A_j - ( A_1+\dots+A_{i-1}) =\\ = (A_1+\dots+A_j) - ( A_1+\dots+A_{i-1}) =\ S_1^j - S_1^{i-1} \ \ \ (S_1^0 =0) \)
(при вычислениях применили принцип "прибавления нуля" angel )
Значит, если предварительно вычислить значения \(S_1^k \) для \(k = 0,1, \dots,n\) , то получиться "ускорить" программу
Изменения проведем в блоке ВВОДА данных и заменим вычисление суммы
(заменим имя списка A на SA, чтобы "отловить" ошибку при "неполной модификации")
 


При модификации можно было допустить некоторые "простые" ошибки (забыть сдвинуть индексы, убрать сдвиг ответа) - большинство нетрудно "отловить" на сравнии ответа с "переборным" ответом)
Время работы сократилось в десять раз, но пока идет "перебор" всех пари (то есть сложность O(n2)) и значит пробовать на файле В ("F27-01_002") смысла нет (n>106 )
Попробуем избавиться от перебора. 
  • Ищем максимальное значение разницы \(S_1^j - S_1^i\), значит одно должно быть максимальным, а другое минимальным
  • Разница двух чисел должна быть кратной m, значит у чисел должны быть одинаковые остатки
  • пары (i,j) могут образовывать только те, для которых \(S_1^i, S_1^j\) имеют одинаковые остатки
Попробуем организовать хранение индексов минимальных \(S_1^i\)и максимальных значений \(S_1^j \) c учетом остатков по модулю m.
Тот факт, что последовательность состоит из положительных чисел, гарантирует строгое неравенство \(S_1^i < S_1^j\ если\ i<j\)
Если все обобщить, то для каждого значения остатка p по модулю m  надо
  • найти минимальное i, такое, что \(S_1^i\ \%\ m\ =\ p\)  
  • найти максимальное i, такое, что \(S_1^j\ \%\ m\ =\ p\)  
  • подсчитать количество k, таких, что \(S_1^k\ \%\ m\ =\ p\)
Сделать это можно на этапе ВВОДА с помощью словарей

В этой задаче необходим подсчет числа подпоследовательностей, сумма элементов которых кратна m.
Для "переборного" решения проблем не было ( +1 и всё). 
В "эффективном" решении считаем Kp  - количество подпоследовательностей, у которых сумма имеет остаток p по модулю m
Всегда  надо добавлять \(C^2_{K_p} = \frac{K_p \cdot (K_p - 1)}{2}\)  - число пар (то есть кол-во подпоследовательностей длины больше 1),а для p=0 ещё добавить Kp (это число подпоследовательностей длины 1)


Теперь сложность программы O(n+m). Можно проверить работу алгоритма на файле В ('F27-01_002.txt')


Подведем итоги:
  • Получено "эффективное" решение "линейной" сложности, получающее ответ за "пару секунд" на файле В (более 1500000 чисел)
  • При получении решения не использовались специальные библиотеки. 
  • Использование "переборного" решения для проверки значительно повышает "надежность результата" и сокращает время на поиск ошибок (отладку программы)
  • предложенный порядок действий и способ решения не претендует на "оптимальность", а лишь иллюстрирует возможный подход к решению
Вы можете попробовать написать своё решение (ниже есть блок для кода), высказать свои замечания и предложить свой вариант "оптимального решения"  
(ограничение по времени 10 секунд)

Прикрепленные файлы
F27-01_001.txt
F27-01_002.txt
Пропустить Навигационные Ссылки.
Чтобы оставить комментарий нужна авторизация
Печать