Реши на C++ через динамическое программирование: П...
創建於:2025年2月24日
創建於:2025年2月24日
Реши на C++ через динамическое программирование:
Представьте, что вы играете в следующую несложную компьютерную игру. На экране нарисованы n кубиков, расположенных в ряд. Каждый кубик окрашен в один из m цветов. Вам разрешается удалить не более чем k кубиков (которые не обязательно идут подряд). После этого оставшиеся кубики сомкнутся и будет произведен подсчет очков. Количество очков, которое вы получите, равно длине максимальной последовательности подряд идущих кубиков одного цвета. Напишите программу, определяющую максимально возможное количество очков, которое вы можете получить.
Обратите внимание: разрешается удалять не более k произвольных кубиков, допустимо не удалять кубики вообще.
Входные данные
В первой строке записаны три целых числа n, m и k (1 ≤ n ≤ 2·105, 1 ≤ m ≤ 105, 0 ≤ k < n). Во второй строке записаны n целых чисел от 1 до m — номера цветов кубиков. Номера цветов разделяются одиночными пробелами.
Выходные данные
Выведите максимально возможное количество очков, которое можно набрать.
Примеры
Входные данныеСкопировать
10 3 2
1 2 1 1 3 2 1 1 2 2
Выходные данныеСкопировать
4
Входные данныеСкопировать
10 2 2
1 2 1 2 1 1 2 1 1 2
Выходные данныеСкопировать
5
Входные данныеСкопировать
3 1 2
1 1 1
Выходные данныеСкопировать
3
Ниже приведён один из наиболее простых и при этом эффективных способов решить эту задачу, используя идею «скользящего окна» (two pointers). Несмотря на то, что в условии упоминается «динамическое программирование», здесь удобнее применять именно технику двух указателей (по сути, это сводится к классическому приёму с вычислением максимально возможного окна при ограничении на количество «лишних» элементов).
Считаем входные данные: — количество кубиков, — количество цветов, — максимально допустимое число удаляемых кубиков, и массив colors
из чисел (цвет каждого кубика).
Для каждого цвета будем хранить отсортированный список позиций в исходном массиве, где встречается этот цвет.
pos[c]
.Далее для каждого цвета мы выполним следующий алгоритм «двух указателей» (скользящего окна) по вектору pos[c]
:
pos[c]
) вычислим:
pos[c][L]
до pos[c][R]
.При каждом расширении окна (когда оно допустимо) мы берём его ширину (это число кубиков цвета подряд после удаления «лишних») и пытаемся обновить глобальный максимум.
В конце выводим найденный глобальный максимум по всем цветам.
pos[c]
равна , поскольку каждый индекс кубика попадает ровно в один список.pos[c]
мы делаем один проход двумя указателями и . Каждый из них сдвигается вперёд не более раз, где — длина списка для цвета .cpp#include <bits/stdc++.h> using namespace std; int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); int n, m, k; cin >> n >> m >> k; vector<int> colors(n); for (int i = 0; i < n; i++) { cin >> colors[i]; // Считаем, что цвета идут от 1 до m // Но для удобства хранения сделаем 0-индексацию colors[i]--; } // Массив векторов: pos[c] будет хранить все индексы i, где colors[i] = c vector<vector<int>> pos(m); // Заполним pos для каждого цвета for (int i = 0; i < n; i++) { pos[colors[i]].push_back(i); } int answer = 1; // в худшем случае ответ минимум 1, если n>0 (или 0, если можно не удалять ничего, но тут n>=1) // Пройдемся по каждому цвету for (int c = 0; c < m; c++) { // Если цвет c ни разу не встречается, пропускаем if (pos[c].empty()) continue; // Два указателя по списку позиций int L = 0; // В pos[c] хранятся индексы данного цвета, уже в отсортированном виде // (так как мы заполняли их в порядке обхода массива) for (int R = 0; R < (int)pos[c].size(); R++) { // Проверяем, не превысили ли мы разрешенное число удаляемых кубиков // while «лишние» > k, сдвигаем L while (true) { // pos[c][R] - pos[c][L] + 1 — общее число кубиков в диапазоне // (R - L + 1) — число кубиков цвета c // Лишние = (общее число в диапазоне) - (число кубиков цвета c) int total = pos[c][R] - pos[c][L] + 1; int countColor = (R - L + 1); int notColor = total - countColor; if (notColor <= k) { break; } else { L++; } } // Здесь мы имеем максимально широкое окно [L..R], которое можно «очистить» до однородного цвета c answer = max(answer, R - L + 1); } } cout << answer << "\n"; return 0; }
pos[c]
— позиции (индексы в исходном массиве) всех кубиков цвета . Они автоматически оказываются отсортированными, так как мы просто перебираем массив слева направо.[L..R]
по pos[c]
соответствует подмножеству кубиков одного цвета, которые в исходном массиве занимают диапазон от pos[c][L]
до pos[c][R]
.total - countColor
, где
total = pos[c][R] - pos[c][L] + 1
— общее количество кубиков (всех цветов) на отрезке исходного массива от pos[c][L]
до pos[c][R]
.countColor = R - L + 1
— число кубиков именно цвета в этом же промежутке (так как мы явно знаем, что в pos[c]
лежат только кубики цвета ).Таким образом, решение работает за при аккуратной реализации и даёт верный результат.
Важно: если , алгоритм тоже корректно работает, просто тогда «лишние» кубики должны быть равны нулю, чтобы расширять окно (то есть кубики цвета уже должны идти подряд в исходном массиве).
Дополнение: Если бы нам требовалось именно «полностью» выписать новую последовательность либо восстановить, какие кубики удалять, это была бы отдельная история. Но по условию достаточно вывести максимальную длину однородного фрагмента после удаления, что и делает данный код.