Уявімо, що ми будуємо "стіни" з блоків однакової висоти.
Пара утворює "коридор", якщо між цими стінами немає більшої стіни. Для розв'язання задачі будемо використовувати монотонний стек. Стек зберігає пари (value, count):
— це висота стіни (значення ).
— скільки підряд однакових елементів цієї висоти вже зустрілося, які можуть утворювати пари з майбутніми такими ж елементами.
Тобто:
Для кожного "блоку однакових чисел" ми запам'ятовуємо тільки два параметри: число і скільки разів воно вже підряд зустрілося.
Коли з'являється новий елемент, ми можемо одразу сказати, скільки пар він утворює: це число рівно для вершини стека.
Наприклад, нехай поточне число дорівнює a = 5, і раніше воно вже зустрічалося рази (тобто на даний момент число a = 5 зустрічається четвертий раз). Припустимо, що між всіма цими входженнями числа знаходяться тільки менші елементи. Тоді кількість нових пар індексів , де — поточний індекс і виконується умова h_i = h_j = a, буде дорівнювати .
При обробці чергового числа h_i:
Якщо число на вершині стека менше h_i, то видаляємо його зі стека.
Якщо число на вершині стека дорівнює h_i і раніше воно зустрічалося разів, то збільшуємо шукану кількість пар індексів на і оновлюємо число появ h_i на x + 1.
Якщо стек порожній або число на вершині стека більше h_i, то додаємо в стек пару (h_i, 1). Це означає, що поточне значення h_i зустрічається перший раз (можливо, воно з'являлося раніше у входній послідовності, але було видалено зі стека через більший елемент).
Приклад
Розглянемо перший тест.
Реалізація алгоритму
Читаємо вхідні дані.
scanf("%d", &n);
vector<int> v(n);
for (i = 0; i < n; ++i)
scanf("%d", &v[i]);У змінній будемо зберігати кількість знайдених пар індексів.
res = 0;Оголосимо стек пар.
stack<pair<int, int>> st;Послідовно обробляємо всі числа масиву.
for (i = 0; i < v.size(); i++)
{Поки на вершині стека знаходиться число, менше , видаляємо його зі стека.
while (!st.empty() && st.top().first < v[i])
st.pop();Якщо на вершині стека знаходиться число, рівне , і воно зустрічалося раніше разів (значення зберігається в st.top().second), то збільшуємо відповідь на . Після цього оновлюємо кількість появ , замінивши його на x + 1.
if (!st.empty() && v[i] == st.top().first)
{
res += st.top().second;
st.top().second += 1;
}
elseЯкщо ж число зустрілося вперше, то додаємо в стек пару (v[i], 1).
st.push({ v[i], 1 });
}Виводимо відповідь.
printf("%lld\n", res);