Восстановление массива по суммам на отрезках
Условия вида «сумма на отрезке равна x» — это рёбра графа. Обход даёт и ответ, и проверку на противоречивость.
3 мин
Дан неизвестный массив длины и набор условий: сумма на полуинтервале равна . Проверить, непротиворечивы ли условия, и если да — предъявить подходящий массив.
Перейти к префиксным суммам
Первый ход — обычный для задач про суммы на отрезках. Пусть — сумма первых элементов, . Тогда условие превращается в
Массив и набор префиксных сумм восстанавливаются друг из друга однозначно, так что задача равносильна.
Где здесь граф
Теперь видно: каждое условие связывает две величины и задаёт разность между ними. Это ребро.
Заведём вершину — по одной на границу . Условие даёт ребро веса и обратное веса .
g[l].push_back({r, x});
g[r].push_back({l, -x});
Пройдя по ребру, мы узнаём значение в его конце, зная значение в начале. Значит, обход из любой вершины расставляет значения по всей её компоненте связности.
Алгоритм
vector<long long> s(n + 1, NONE);
for (int start = 0; start <= n; start++) {
if (s[start] != NONE) continue;
s[start] = 0; // свободная компонента: якорь произвольный
vector<int> st{start};
while (!st.empty()) {
int v = st.back(); st.pop_back();
for (auto [u, c] : g[v]) {
if (s[u] == NONE) { s[u] = s[v] + c; st.push_back(u); }
else if (s[u] != s[v] + c) return false; // противоречие
}
}
}
for (int i = 0; i < n; i++) a[i] = s[i + 1] - s[i];
Проверено: на 200 000 наборов условий найденный массив всегда удовлетворял всем условиям, а обнаруженные противоречия подтвердились независимой проверкой потенциалов.
Три вещи, которые тут происходят
Противоречие — это цикл с ненулевой суммой весов. Придя в вершину вторым маршрутом и получив другое значение, мы обнаружили именно его.
Разные компоненты независимы. Если условия не связывают начало массива с концом, значения в разных компонентах можно выбирать произвольно. В коде якорь ставится в ноль — годится любое число.
Свобода внутри компоненты только одна. Зафиксировав одно значение, мы определяем все остальные в компоненте. Это в точности то, что даёт остовное дерево компоненты.
Вариант с ограничением на знак
Часто дополнительно требуют, чтобы все элементы были неотрицательны.
В компоненте, содержащей вершину 0, всё уже определено — проверяем и всё. А вот якоря свободных компонент можно двигать, и этим стоит воспользоваться: ставим значение так, чтобы разность с уже известным соседом слева была нулевой. Это соответствует нулевым элементам массива между известными кусками — минимально возможным при требовании неотрицательности.
Общий приём
Узнаётся так: условия связывают величины попарно и задают разность. Тогда величины — вершины, условия — рёбра, ответ — обход.
Так же решаются:
- «известны разности между парами чисел, восстановить числа»;
- «известно, кто кого тяжелее и на сколько, расставить веса»;
- система сравнений по модулю.
Если вместо равенств даны неравенства , приём тот же, но обход заменяется на Форда — Беллмана: решение существует тогда и только тогда, когда нет отрицательного цикла. Это называется системой разностных ограничений.