E. Дружеские подарки ограничение по времени на тес...

Tạo vào: 12 tháng 6, 2026

Trả lời bằng GPT-5.5 bởi Chat01

Câu hỏi

E. Дружеские подарки
ограничение по времени на тест
3 секунды
ограничение по памяти на тест
512 мегабайт
Арсений решил порадовать своих друзей — Дабира и Егора. Для этого он решил подарить каждому из них по массиву чисел одинаковой длины. Массив b называется хорошим, если его элементы можно переставить так, что для всех i>1 верно bi−bi−1=1.

Арсений хочет, чтобы Дабир и Егор могли играть с этими массивами. Для этого должны быть выполнены следующие условия:
Каждый из подаренных массивов является хорошим.
Если записать один массив за вторым(другими словами, сконкатенировать), полученный массив окажется хорошим.
У Арсения уже есть массив a длины n. Он планирует вырезать оба массива из a, то есть выбрать в нём два непересекающихся отрезка одинаковой длины. Помогите Арсению определить максимальную возможную длину полученных массивов.
Входные данные
В первой строке находится одно целое число t (1≤t≤1000) — количество наборов входных данных.
Далее следуют t наборов входных данных.
Первая строка каждого набора входных данных содержит одно целое число n (1≤n≤6000).
Вторая строка содержит n целых чисел a1,a2,…,an (1≤ai≤n).
Гарантируется, что сумма значений n по всем наборам входных данных не превосходит 6000.
Выходные данные
Для каждого набора входных данных выведите целое число, обозначающее максимальную возможную длину массивов.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);

text
int t; cin >> t; while (t--) { int n; cin >> n; vector<int> a(n); for (int i = 0; i < n; ++i) cin >> a[i]; vector< int ma = 0, cur = 1; for (int i = 1; i < n; ++i) { if (a[i] - a[i - 1] == 1) cur++; else { if (cur > ma) ma = cur; cur = 1; } } if (cur > ma) ma = cur; cur = a[n - 1]; for (int i = n - 2; i >= 0; --i) { if (a[i] - a[i + 1] == 1) cur++; else { if (cur > ma) ma = cur; cur = 1; } } if (cur > ma) ma = cur; cout << ma / 2 << '\n'; } return 0;

}

что у меня не так? можешь исправить мой код, МИНИМАЛЬНО его изменяя и ОЧЕНЬ ПОДРОБНОО объясняя все исправления и мои ошибки

Suy nghĩ

Разберу именно по твоему коду: там есть одна явная синтаксическая ошибка, но главная проблема — сама идея проверяет не то свойство массива. Исправленный вариант получится с заменой центральной логики, но остальной каркас оставлю почти тем же.

Thought for 22s

Trả lời

У тебя проблема не в мелком баге, а в том, что код проверяет не то условие.

Вот исправленный код с сохранением твоего каркаса main / t / n / a / cout:

cpp
#include <iostream> #include <vector> #include <algorithm> #include <set> using namespace std; int main() { ios_base::sync_with_stdio(0); cin.tie(0); int t; cin >> t; while (t--) { int n; cin >> n; vector<int> a(n); for (int i = 0; i < n; ++i) cin >> a[i]; int ans = 0; for (int k = n / 2; k >= 1; --k) { vector<int> mnPos(n + 2, n + 1); vector<int> mxPos(n + 2, -1); vector<int> cnt(n + 1, 0); int different = 0; multiset<int> s; for (int i = 0; i < n; ++i) { s.insert(a[i]); if (cnt[a[i]] == 0) different++; cnt[a[i]]++; if (i >= k) { s.erase(s.find(a[i - k])); cnt[a[i - k]]--; if (cnt[a[i - k]] == 0) different--; } if (i >= k - 1) { int l = i - k + 1; int mn = *s.begin(); int mx = *s.rbegin(); if (different == k && mx - mn + 1 == k) { mnPos[mn] = min(mnPos[mn], l); mxPos[mn] = max(mxPos[mn], l); } } } bool ok = false; for (int x = 1; x + k <= n; ++x) { if (mnPos[x] == n + 1 || mnPos[x + k] == n + 1) continue; if (mnPos[x] + k <= mxPos[x + k]) ok = true; if (mnPos[x + k] + k <= mxPos[x]) ok = true; } if (ok) { ans = k; break; } } cout << ans << '\n'; } return 0; }

Что у тебя было не так:

  1. Синтаксическая ошибка
cpp
vector<

Эта строка просто не дописана, из-за неё код не компилируется.

  1. Ты проверял только подряд идущие элементы в исходном порядке
cpp
if (a[i] - a[i - 1] == 1)

Но по условию массив хороший, если его можно переставить.

Например:

cpp
[3, 1, 2]

Это хороший массив, потому что его можно переставить в:

cpp
[1, 2, 3]

А твой код такой массив не засчитает.

  1. Хороший массив — это не возрастающий отрезок

Массив длины k хороший, если:

cpp
все элементы различны max - min + 1 == k

Например:

cpp
[4, 2, 3]

min = 2, max = 4, длина 3.

cpp
4 - 2 + 1 == 3

Все элементы разные, значит массив хороший.

  1. Ты вообще не проверял два отрезка

Нужно выбрать два непересекающихся отрезка одинаковой длины.

Твой код просто искал максимальный возрастающий/убывающий кусок и делил его на 2:

cpp
cout << ma / 2 << '\n';

Но это не соответствует условию.

  1. Конкатенация тоже должна быть хорошей

Если один отрезок содержит числа:

cpp
[1, 2, 3]

а второй:

cpp
[4, 5, 6]

то вместе они дают хороший массив длины 6.

То есть их диапазоны значений должны быть соседними:

cpp
[x, x + k - 1] [x + k, x + 2k - 1]

Именно это проверяется здесь:

cpp
for (int x = 1; x + k <= n; ++x) { if (mnPos[x] == n + 1 || mnPos[x + k] == n + 1) continue;
  1. Проверка непересечения отрезков

Если первый отрезок начинается в l, то он занимает:

cpp
[l, l + k - 1]

Чтобы он не пересекался со вторым, который начинается в r, надо:

cpp
l + k <= r

Поэтому в коде:

cpp
if (mnPos[x] + k <= mxPos[x + k]) ok = true; if (mnPos[x + k] + k <= mxPos[x]) ok = true;

mnPos[value] — самая левая позиция хорошего отрезка с минимумом value.

mxPos[value] — самая правая позиция такого отрезка.

  1. Почему идём от n / 2 вниз

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

Поэтому:

cpp
k <= n / 2

И как только нашли подходящий k, сразу делаем:

cpp
ans = k; break;

потому что это уже максимальный ответ.

Chia sẻ Q&A này