Игорь решил заняться спортом и изменить свой вес. ...
Created on: August 27, 2025
Answered using GPT-5 Thinking by Chat01
Created on: August 27, 2025
Answered using GPT-5 Thinking by Chat01
Игорь решил заняться спортом и изменить свой вес.
У него есть календарь на
дней, в каждой клетке которого записано число
. Это значит, что в день
Игорь изменит свой вес на
килограмм с помощью определённых действий.
Игорь ненавидит число
, поэтому он не хочет, чтобы нашелся такой непустой подотрезок массива
, сумма элементов которого была равна
.
Ваша задача — найти, какое минимальное количество дней с тренировками нужно добавить (вставить день в начало, конец, или между двумя днями в календаре), чтобы условие выполнялось.
Гарантируется, что в массиве нет числа
.
Обратите внимание, что числа на листах календаря, которые вы вставляете, могут быть абсолютно любыми.
Формат входных данных
В первой строчке вводятся числа
и
— количество тренировок и число, которое Игорь ненавидит.
Во второй строчке вводятся
чисел
,
— изменения веса Игоря.
Формат результата
Выведите единственное число — ответ на задачу.
Примеры
Входные данные
5 1
1000000 1000000 1000000 1000000 1000000
Результат работы
c++
pythondef solve(n,x,a): seen = {0} pref = 0 ans = 0 for v in a: nxt = pref + v if (nxt - x) in seen: ans += 1 seen = {0} pref = 0 pref += v seen.add(pref) else: pref = nxt seen.add(pref) return ans print(solve(5,1,[1000000]*5)) print(solve(3,5,[2,3,2])) # subarray [2,3] sum=5; Need 1 insertion before 2nd?
pythonprint(solve(3,0,[1,-1,2]))
Вот краткое и рабочее решение.
Идея:
Почему это минимально: каждый раз, когда условие срабатывает, без немедленной вставки появится запрещённая сумма, то есть хотя бы одна вставка неизбежна. Жадный разрыв в самый ранний момент даёт минимальное количество вставок.
Сложность: по времени и по памяти.
cpp#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; long long x; if (!(cin >> n >> x)) return 0; vector<long long> a(n); for (int i = 0; i < n; ++i) cin >> a[i]; unordered_set<long long> seen; seen.reserve((size_t)n * 2 + 10); seen.insert(0); // префикс внутри текущего сегмента long long pref = 0; // префикс внутри текущего сегмента int ans = 0; for (int i = 0; i < n; ++i) { long long next_pref = pref + a[i]; if (seen.count(next_pref - x)) { // вставляем день прямо перед a[i] ++ans; seen.clear(); seen.insert(0); pref = a[i]; // новый сегмент начинается перед a[i] // гарантировано, что a[i] != x, значит конфликта тут не будет seen.insert(pref); } else { pref = next_pref; seen.insert(pref); } } cout << ans << '\n'; return 0; }
Пример из условия:
textВвод: 5 1 1000000 1000000 1000000 1000000 1000000 Вывод: 0
(ни один подотрезок не суммируется в 1, поэтому вставки не нужны).
Игорь решил заняться спортом и изменить свой вес.
У него есть календарь на
дней, в каждой клетке которого записано число
. Это значит, что в день
Игорь изменит свой вес на
килограмм с помощью определённых действий.
Игорь ненавидит число
, поэтому он не хочет, чтобы нашелся такой непустой подотрезок массива
, сумма элементов которого была равна
.
Ваша задача — найти, какое минимальное количество дней с тренировками нужно добавить (вставить день в начало, конец, или между двумя днями в календаре), чтобы условие выполнялось.
Гарантируется, что в массиве нет числа
.
Обратите внимание, что числа на листах календаря, которые вы вставляете, могут быть абсолютно любыми.
Формат входных данных
В первой строчке вводятся числа
и
— количество тренировок и число, которое Игорь ненавидит.
Во второй строчке вводятся
чисел
,
— изменения веса Игоря.
Формат результата
Выведите единственное число — ответ на задачу.
Примеры
Входные данные
5 1
1000000 1000000 1000000 1000000 1000000
Результат работы
0
Входные данные
5 4
-4 3 5 0 1
Результат работы
1
Примечания
В первом примере нет подотрезков массива с суммой
.
Во втором примере можно вставить лист с числом
между
и
днем. Тогда массив
превратится в:
Легко проверить, что в данном массиве нет подотрезка с суммой
.
Рассмотрим задачу подробно.
Дан массив из n
чисел a_1, a_2, ..., a_n
и число x
, которое Игорь ненавидит.
Нужно вставить минимальное количество чисел (в любое место), чтобы не было ни одного непустого подотрезка массива с суммой, равной x
.
x
.Используем префиксные суммы.
Любой подотрезок с суммой x
означает:
prefix_sum[j] - prefix_sum[i-1] == x
=>prefix_sum[j] - x == prefix_sum[i-1]
То есть при добавлении нового элемента мы проверяем:
существует ли уже такой префикс, что
prefix_sum_now - x == existing_prefix
Если да, значит есть подотрезок с суммойx
.
В этом случае мы вставим новый день, чтобы разорвать такой подотрезок.
s
.seen
из всех префиксов, встреченных в текущем сегменте.s - x ∈ seen
, то вставляем новый элемент (считаем как новую секцию).seen
, начинаем отслеживать с текущего элемента.text5 4 -4 3 5 0 1
Пояснение:
префикс = 4
, а 4 - 4 = 0
— уже есть => вставкаpythondef min_insertions_to_avoid_sum_x(n, x, a): seen = set() seen.add(0) prefix = 0 ans = 0 for val in a: prefix += val if (prefix - x) in seen: # нужно вставить день, начинаем новый сегмент ans += 1 seen = {0} prefix = val seen.add(prefix) else: seen.add(prefix) return ans # Примеры print(min_insertions_to_avoid_sum_x(5, 1, [1000000, 1000000, 1000000, 1000000, 1000000])) # 0 print(min_insertions_to_avoid_sum_x(5, 4, [-4, 3, 5, 0, 1])) # 1
Метод работает за по времени и памяти.
Мы гарантированно получаем минимальное количество вставок, чтобы в массиве не было подотрезков с суммой x
.
Хочешь — могу переписать решение на C++, Java или другом языке.
сделай на с++
Вот полный код на C++, реализующий описанный алгоритм:
cpp#include <iostream> #include <unordered_set> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; long long x; cin >> n >> x; long long* a = new long long[n]; for (int i = 0; i < n; ++i) cin >> a[i]; unordered_set<long long> seen; seen.insert(0); // Префикс 0 в начале long long prefix = 0; int insertions = 0; for (int i = 0; i < n; ++i) { prefix += a[i]; if (seen.count(prefix - x)) { // Найдена запрещённая сумма -> вставляем элемент ++insertions; seen.clear(); seen.insert(0); prefix = a[i]; // начинаем с текущего элемента seen.insert(prefix); } else { seen.insert(prefix); } } cout << insertions << '\n'; delete[] a; return 0; }
Ввод:
text5 4 -4 3 5 0 1
Вывод:
1
unordered_set
для хранения префиксов в текущем сегменте.x
), делается вставка и начинается новый сегмент.Если нужно — могу переписать это в стиле class
, или с пояснениями к каждому шагу.