Условие
В подземных норах в долине рядом со скалами Крейд-Моор долгое время жили в мире и согласии два гномьих племени. Гномы обоих племен работали в шахтах, добывая драгоценные камни. Первое племя добывало исключительно изумруды, а второе племя — рубины. Однажды в честь великого праздника Файрвинд гномы решили принести в дар своей богине Мирабель цепочку из изумрудов и рубинов. Самые искусные кузнецы обоих племен работали над созданием этой цепочки, собирая на ней один за одним драгоценные камни. Но как только работа была окончена, решили вожди племен пересчитать камни каждого вида. Ведь если каких-то камней окажется меньше, то богиня может отвернуться от племени, которое пожадничало. Чтобы избежать подобных последствий, было решено подарить некоторый непустой фрагмент цепочки (то есть цепь, состоящую из нескольких камней, расположенных друг за другом в исходной цепочке), в котором будет рубинов ровно столько же, сколько и изумрудов. Возможно это может быть сделано несколькими способами. Для того, чтобы узнать сколько таких способов существует, гномы обратились за помощью к вам.
Напишите программу, которая находит количество способов, которыми можно выбрать подходящий фрагмент.
Входные данные
В единственной строке задается последовательность камней в исходной цепочке: символ E обозначает изумруд, символ R — рубин. Количество символов в строке не превышает $500000$.
Выходные данные
Выведите количество способов, которыми можно выбрать фрагмент с одинаковым количеством изумрудов и рубинов.
Тесты
№ | ввод | вывод |
---|---|---|
1 | REER | 3 |
2 | REERREER | 12 |
3 | RRRRRRRR | 0 |
4 | EREREERERERREREREEERERERERERRREREREERERERERE | 273 |
5 | REEERREE | 7 |
Код
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include <iostream> #include <map> using namespace std; int main() { int cnt = 0; char buf; map<int, long long> mp; mp[0] = 1; while(cin >>buf) { if(buf=='R') cnt++; else cnt--; mp[cnt]++; } long long answer = 0; for(auto e: mp) { answer += e.second*(e.second-1)/2; } cout <<answer; } |
Компактный код
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include #include <map> using namespace std; int main() { int cnt = 0; char buf; map mp; mp[0] = 1; while(cin >>buf) mp[buf=='R'?++cnt:--cnt]++; long long a = 0; for(auto e: mp) a += e.second*(e.second-1)/2; cout <<a; } |
Решение
Составим массив из $n+1$ чисел, каждое из которых будет располагаться в месте возможного начала или конца фрагмента цепочки, который гномы должны вручить богине. Число в самом начале цепочки возьмём равным $0$, а все следующие числа будут представлять из себя количество R минус количество E, встречающихся в фрагменте с начала до этого числа.
На таком массиве наглядно видно, что правильным фрагментом будет любой, начинающийся и кончающийся одинаковым числом, ведь это значит что между этими числами равное количество как R($+1$), так и E($-1$), которые сокращаются.
Так как нам не важны конкретные правильные фрагменты, а только их суммарное количество, нам будет достаточно знать, сколько раз в массиве встречается то или иное число. В коде эту информацию хранит ассоциативная таблица
mp. Запись
mp[cnt]++; создаёт новый равный нулю элемент по ключу
cnt, если раньше в структуре его не было, после чего инкрементирует значение.
Сам же массив воспроизводится на ходу из ввода, в переменной
cnt. В конце программы количество фрагментов считается как сумма $\frac{n(n-1)}{2}$, где $n$ —
mp[i] для всех встречавшихся в массиве чисел.
Для отправки комментария необходимо войти на сайт.