Реши на C++ через динамическое программирование: П...

बनाया गया: 24 फ़रवरी 2025

का उपयोग करके उत्तर दिया गया O1 द्वारा Chat01

प्रश्न

Реши на 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

विचार

Identifying the problem

I’m fact-checking the issue of forming the longest contiguous subsequence of cubes of the same color, aiming to maximize the score by allowing the removal of up to k arbitrary cubes.

Gathering and analyzing positions

I’m gathering positions of cubes of color c. Then, I’ll identify the longest contiguous subsequence within a window of length L in the original array, allowing up to k cubes of other colors.

Identifying optimal coverage

I’m examining how to maximize the count of color c cubes in a range of length L, by efficiently removing up to k cubes of other colors.

Optimizing the range

I’m using two pointers to find the longest range of color c cubes in positions from pos[i] to pos[j], ensuring the number of cubes of other colors remains within k.

Finding the optimal solution

I’m noting that by focusing on colors c within the array and applying the two-pointer method to their positions, we can efficiently determine the maximum contiguous subsequence for each color.

Ensuring efficiency

I’m thinking through the single-pass approach to find the longest subsequence for each color, ensuring that the total complexity remains O(n) and is feasible given the constraints.

Mapping the strategy

I’m outlining the use of an array of vectors or an unordered map to store positions, applying the two-pointer approach for each color, and identifying the longest subarray within constraints.

Reasoned for 18 seconds

उत्तर

Ниже приведён один из наиболее простых и при этом эффективных способов решить эту задачу, используя идею «скользящего окна» (two pointers). Несмотря на то, что в условии упоминается «динамическое программирование», здесь удобнее применять именно технику двух указателей (по сути, это сводится к классическому приёму с вычислением максимально возможного окна при ограничении на количество «лишних» элементов).

Идея решения

  1. Считаем входные данные: nn — количество кубиков, mm — количество цветов, kk — максимально допустимое число удаляемых кубиков, и массив colors из nn чисел (цвет каждого кубика).

  2. Для каждого цвета будем хранить отсортированный список позиций в исходном массиве, где встречается этот цвет.

    • Пусть для цвета cc список таких позиций называется pos[c].
    • Все эти позиции запоминаем (например, в 0-индексации).
  3. Далее для каждого цвета cc мы выполним следующий алгоритм «двух указателей» (скользящего окна) по вектору pos[c]:

    • Пусть этот вектор имеет длину \ell. Тогда мы заведём два индекса LL и RR (оба в начале указывают на 0).
    • Идём правым указателем RR слева направо. Для текущего подотрезка от LL до RR (внутри pos[c]) вычислим:
      • число кубиков цвета c внутри выбранного подотрезка=RL+1 \text{число кубиков цвета } c \text{ внутри выбранного подотрезка} = R - L + 1.
      • Позиции этих кубиков в исходном массиве занимают диапазон от pos[c][L] до pos[c][R].
        Тогда общее количество кубиков (всех цветов) в этом диапазоне: длина=(pos[c][R]pos[c][L])+1. \text{длина} = (\text{pos}[c][R] - \text{pos}[c][L]) + 1. Из них «лишние» (не цвета cc): лишние=длина(RL+1)=(pos[c][R]pos[c][L]+1)(RL+1). \text{лишние} = \text{длина} - (R - L + 1) = (\text{pos}[c][R] - \text{pos}[c][L] + 1) - (R - L + 1). При этом мы можем удалить не более kk таких лишних кубиков.
    • Если лишниеk\text{лишние} \le k, то текущее окно допустимо, и мы можем попытаться расширить его, сдвинув RR на 1 вправо.
    • Если лишние>k\text{лишние} > k, то надо сужать окно, увеличивая LL.
  4. При каждом расширении окна (когда оно допустимо) мы берём его ширину (RL+1)(R-L+1) (это число кубиков цвета cc подряд после удаления «лишних») и пытаемся обновить глобальный максимум.

  5. В конце выводим найденный глобальный максимум по всем цветам.

Почему это работает быстро

  • Все позиции кубиков каждого цвета мы собираем один раз (сложность O(n)O(n) по всему входному массиву).
  • Суммарная длина всех списков pos[c] равна nn, поскольку каждый индекс кубика попадает ровно в один список.
  • Для каждого списка pos[c] мы делаем один проход двумя указателями LL и RR. Каждый из них сдвигается вперёд не более \ell раз, где \ell — длина списка для цвета cc.
    Следовательно, во всей программе суммарно все перемещения LL и RR по всем цветам составят O(n)O(n).
  • Итого общее время работы O(n)O(n) (при условии, что мы перебираем только те цвета, которые реально встречаются в массиве).

Пример кода на 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 &laquo;лишние&raquo; > 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], которое можно &laquo;очистить&raquo; до однородного цвета c answer = max(answer, R - L + 1); } } cout << answer << "\n"; return 0; }

Пояснение

  • pos[c] — позиции (индексы в исходном массиве) всех кубиков цвета cc. Они автоматически оказываются отсортированными, так как мы просто перебираем массив слева направо.
  • Отрезок [L..R] по pos[c] соответствует подмножеству кубиков одного цвета, которые в исходном массиве занимают диапазон от pos[c][L] до pos[c][R].
  • «Лишних» кубиков между ними (тех, что не цвета cc) получается total - countColor, где
    • total = pos[c][R] - pos[c][L] + 1 — общее количество кубиков (всех цветов) на отрезке исходного массива от pos[c][L] до pos[c][R].
    • countColor = R - L + 1 — число кубиков именно цвета cc в этом же промежутке (так как мы явно знаем, что в pos[c] лежат только кубики цвета cc).
  • Если лишниеk\text{лишние} \le k, значит мы можем удалить все эти «лишние» кубики за счёт нашего лимита kk и получить подряд идущую цепочку из RL+1R-L+1 кубиков цвета cc.
  • Перебираем все возможные варианты такого окна для каждого цвета и берём максимум.

Таким образом, решение работает за O(n)O(n) при аккуратной реализации и даёт верный результат.


Важно: если k=0k = 0, алгоритм тоже корректно работает, просто тогда «лишние» кубики должны быть равны нулю, чтобы расширять окно (то есть кубики цвета cc уже должны идти подряд в исходном массиве).


Дополнение: Если бы нам требовалось именно «полностью» выписать новую последовательность либо восстановить, какие кубики удалять, это была бы отдельная история. Но по условию достаточно вывести максимальную длину однородного фрагмента после удаления, что и делает данный код.

इस प्रश्नोत्तर को साझा करें