НОД, Сумма, УмножитьИмя входного файла: стандартны...
Creado el: 12 de noviembre de 2026
Creado el: 12 de noviembre de 2026
НОД, Сумма, УмножитьИмя входного файла:
стандартный вводИмя выходного файла:
стандартный выводОграничение по времени:
3 секундыОграничение по памяти:
256 мегабайтВам дан массив a, состоящий из n целых чисел. Вам также даны q запросов [l;r]. Для каждогозапроса найдите максимальное значение sum[tl;tr] gcd[tl;tr] среди всех пар (tl;tr), где
• l 6 tl 6 tr 6 r;• sum[tl;tr] сумма всех чисел в отрезке [tl;tr];• gcd[tl;tr] наибольший общий делитель всех чисел в отрезке [tl;tr].
Наибольший общий делитель двух чисел a и b это наибольшее положительное целое число x,которое делит и a, и b.Наибольший общий делитель множества чисел это наибольшее положительное целое число x,которое делит все элементы множества.Формат входных данныхПервая строка содержит два целых числа n, q (1 6 n;q 6 2 100000) количество элементов вмассиве и количество запросов соответственно.Вторая строка содержит n целых чисел a
i
(1 6 a
i
6 6 10
6) описание массива.Каждая из следующих q строк содержит два целых числа l
j
, r
j
(1 6 l
j
6 r
j
6 n) описаниезапросов.Формат выходных данныхВыведите q целых чисел ответы на запросы.Система оценкиБаллы за каждую подзадачу начисляются только в случае, если все тесты для этой подзадачии необходимых подзадач успешно пройдены.
Подзадача Баллы
Дополнительныеограничения
Необходимыеподзадачи
Информацияо проверке0
0
Тесты из условия
полная1
4
n 6 3
первая ошибка2
8
n;q 6 1000
первая ошибка3
5
n 6 1000
2
первая ошибка4
17
n;q 6 100000
2
первая ошибка5
14
n 6 100000
2, 3, 4
первая ошибка6
5
Все a
i
6 20
первая ошибка7
7
Все a
i
6 1000
6
первая ошибка8
16
Все l
j
= 1
первая ошибка9
24
нет
1 – 8
первая ошибка
Страница 1 из 2Примерыстандартный ввод
стандартный вывод3 23 3 21 32 3
189
8 62 4 8 8 8 2 4 161 82 53 42 47 73 6
2
Как решать когда максимальный элемент до 20
sum — сумму всего отрезка, если все его элементы разрешены;pref — максимальную сумму разрешённого префикса;suff — максимальную сумму разрешённого суффикса;best — максимальную сумму разрешённого подотрезка.best на этом отрезке и обновляем ответ:sum/pref/suff/best проще реализовать и доказать.Если все , можно использовать то, что НОД любого подотрезка тоже не превосходит 20.
Получим решение за с помощью дерева отрезков.
Нужно найти
Зафиксируем возможный НОД , где .
Если , то все элементы на отрезке делятся на .
Поэтому можно для каждого искать максимальную сумму подотрезка, состоящего только из чисел, кратных .
Заметь, что мы не требуем, чтобы НОД был ровно . Это не мешает!
Действительно, если у найденного подотрезка НОД равен , причём , то
А когда мы переберём , этот подотрезок тоже будет рассмотрен. Значит, максимум получится правильным.
Для каждого построим дерево отрезков.
В дереве для :
В каждой вершине дерева храним:
sum — сумму всего отрезка, если все его элементы разрешены;pref — максимальную сумму разрешённого префикса;suff — максимальную сумму разрешённого суффикса;best — максимальную сумму разрешённого подотрезка.Объединяем две вершины стандартно, как в задаче о максимальной сумме подотрезка:
Запрещённые позиции удобно представлять значением для всех четырёх полей листа. При объединении используем обычные формулы для максимальной суммы подотрезка.
Для запроса перебираем все от 1 до 20, получаем best на этом отрезке и обновляем ответ:
Построение 20 деревьев:
Каждый запрос — 20 обращений к деревьям:
Итого:
Память:
При это вполне подходит.
Дополнительное упрощение: поскольку все положительные, для фиксированного максимальная сумма достигается на целом непрерывном блоке чисел, делящихся на . Поэтому вместо дерева максимальной суммы подотрезка можно хранить информацию о таких блоках, но описанное решение с sum/pref/suff/best проще реализовать и доказать.
А полное решение
Вот полное решение на C++17 для подзадачи, где .
Идея: перебираем возможный НОД от 1 до 20. Для каждого строим дерево отрезков, которое находит максимальную сумму подотрезка, состоящего только из чисел, кратных .
cpp#include <bits/stdc++.h> using namespace std; using ll = long long; const ll INF = (1LL << 60); const int K = 20; struct Node { ll sum, pref, suff, best; }; Node emptyNode() { return {0, -INF, -INF, -INF}; } Node mergeNode(Node a, Node b) { Node c; c.sum = a.sum + b.sum; c.pref = max(a.pref, a.sum + b.pref); c.suff = max(b.suff, b.sum + a.suff); c.best = max({a.best, b.best, a.suff + b.pref}); return c; } struct SegTree { int n; vector<Node> t; SegTree(const vector<int>& a, int d) { n = (int)a.size() - 1; t.resize(4 * n); build(1, 1, n, a, d); } void build(int v, int l, int r, const vector<int>& a, int d) { if (l == r) { if (a[l] % d == 0) { ll x = a[l]; t[v] = {x, x, x, x}; } else { t[v] = {-INF, -INF, -INF, -INF}; } return; } int m = (l + r) / 2; build(v * 2, l, m, a, d); build(v * 2 + 1, m + 1, r, a, d); t[v] = mergeNode(t[v * 2], t[v * 2 + 1]); } Node query(int v, int l, int r, int ql, int qr) { if (ql <= l && r <= qr) { return t[v]; } int m = (l + r) / 2; if (qr <= m) return query(v * 2, l, m, ql, qr); if (ql > m) return query(v * 2 + 1, m + 1, r, ql, qr); Node a = query(v * 2, l, m, ql, qr); Node b = query(v * 2 + 1, m + 1, r, ql, qr); return mergeNode(a, b); } ll query(int l, int r) { return query(1, 1, n, l, r).best; } }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, q; cin >> n >> q; vector<int> a(n + 1); for (int i = 1; i <= n; i++) { cin >> a[i]; } vector<SegTree> trees; trees.reserve(K); for (int d = 1; d <= K; d++) { trees.emplace_back(a, d); } while (q--) { int l, r; cin >> l >> r; ll ans = 0; for (int d = 1; d <= K; d++) { ll s = trees[d - 1].query(l, r); if (s > 0) { ans = max(ans, s * d); } } cout << ans << '\n'; } return 0; }
Рассмотрим произвольный подотрезок с НОД .
Поскольку все , имеем .
Когда алгоритм рассматривает , все элементы этого подотрезка делятся на . Значит, дерево для найдёт сумму не меньше, чем .
Поэтому ответ алгоритма не меньше оптимального.
С другой стороны, пусть дерево для некоторого выбрало подотрезок с суммой . Все элементы этого подотрезка делятся на , поэтому его настоящий НОД кратен .
Следовательно,
То есть значение, найденное алгоритмом, не превосходит ответа исходной задачи.
Из двух неравенств получаем, что алгоритм находит точный максимум.
Важно: это решение только для подзадачи , а не для полных ограничений .
В реализации используется long long, поскольку ответ может достигать порядка , а в общей задаче — значительно больше.