Правильные подматрицы задачи
Erstellt am: 18. Januar 2025
Erstellt am: 18. Januar 2025
Дана матрица (таблица) из п строк и т столбцов, заполненная строчными буквами латинского алфавита.
Назовем матрицу правильной, если в ней встречаются ровно две различные буквы, и они расположены в шахматном порядке (одна буква на местах белых клеток, вторая — чёрных).
Следующие матрицы являются правильными:
0 х 0
х 0 x
0 x 0
количество строк и
В каждой из следующих п строк задана последовательность, состоящая из т строчных бу
латинского алфавита.
Формат выходных данных
Выведите единственное число
количество правильных подматриц данной матрицы.
примеры:
ввод:
2 2
ab
ba
вывод:
5
ввод:
2 2
aa
aa
вывод:
0
реши эту задачу на питоне
Ниже приведён один из возможных путей решения задачи на Python с учётом ограничений .
Основная идея:
Подсчитать все «правильные» подматрицы высотой с помощью «инкрементального» прохода по строкам:
Такой способ позволяет за (с учётом аккуратной обработки) перебрать все прямоугольники высотой .
Отдельно учесть «правильные» подматрицы высотой .
Полный код, реализующий оба шага, может выглядеть довольно объёмно, поэтому приведём один из вариантов реализации, достаточно подробно прокомментированный.
pythondef solve(): import sys data = sys.stdin.read().strip().split() n, m = map(int, data[:2]) # Далее идут n строк по m символов matrix = data[2:] # ----------------------------------------------------------------------------- # Часть 1: считаем количество "правильных" подматриц высотой >= 2 # ----------------------------------------------------------------------------- # # Идея: # 1) Фиксируем r1 (верхняя строка). # 2) Для r2 от r1 до n-1 накапливаем информацию о каждом столбце: # - col0Letter[c]: какой символ у "белых" ((i+c)%2 == 0) клеток данного столбца # (если раньше все белые клетки были одинаковы, иначе -1 означает "невалидно", # -2 означает "ещё не встречали белую клетку"? -- ниже упростим, инициализируем сразу # при добавлении первой строки) # - col1Letter[c]: аналогично для "чёрных" ((i+c)%2 == 1) клеток. # 3) Получив для каждого столбца c пару (col0Letter[c], col1Letter[c]) (если не -1), # группируем подряд идущие столбцы с одинаковой парой (A, B), где A != B, A,B != -1. # Пусть длина такого блока L, он даёт L*(L+1)//2 подматриц. # # Ограничение: смотрим только подматрицы, у которых количество строк (r2-r1+1) >= 2, # поскольку иначе один столбец не может содержать и "белые", и "чёрные" клетки. # answer_multirow = 0 # col0Letter[c] и col1Letter[c] будем хранить как либо конкретный символ (char), # либо None, если уже столкнулись с противоречием в этом столбце для цвета. # Начальное значение тоже None, пока не заполним первой строкой. for r1 in range(n): # Инициализируем массивы col0Letter = [None]*m col1Letter = [None]*m # Будем наращивать нижнюю границу r2 for r2 in range(r1, n): # Добавляем строку r2 к текущему "вертикальному" прямоугольнику h = r2 - r1 + 1 # высота текущего подпрямоугольника # Пройдемся по всем столбцам и обновим col0Letter[c], col1Letter[c] for c in range(m): if ((r2 + c) % 2) == 0: # Это "белая" клетка по шахматному цвету if col0Letter[c] is None: # Ещё не было белой клетки в этом столбце (для текущего набора строк) col0Letter[c] = matrix[r2][c] else: # Проверяем совпадение if col0Letter[c] != matrix[r2][c]: col0Letter[c] = None # конфликт, инвалидируем else: # "Чёрная" клетка if col1Letter[c] is None: col1Letter[c] = matrix[r2][c] else: if col1Letter[c] != matrix[r2][c]: col1Letter[c] = None # Если высота = 1, столбец содержит клетки только одного цвета, # значит в таком столбце мы НЕ можем сразу же получить "белые+чёрные клетки". # Поэтому подматрицы высотой = 1 мы здесь не учитываем. # Считаем только если h >= 2: if h >= 2: # Теперь нужно за один проход по столбцам посчитать, # сколько подряд идущих имеют одинаковую пару (col0Letter, col1Letter), # причём обе буквы не None и отличаются друг от друга. current_pair = None current_len = 0 for c in range(m): A = col0Letter[c] B = col1Letter[c] # Проверим валидность if A is None or B is None or A == B: # Невалидная пара, обрываем текущую серию if current_pair is not None: # добавляем количество подотрезков answer_multirow += current_len * (current_len + 1) // 2 current_pair = None current_len = 0 else: # Пара (A, B) валидна if current_pair == (A, B): current_len += 1 else: # Закрываем предыдущую серию if current_pair is not None: answer_multirow += current_len * (current_len + 1) // 2 current_pair = (A, B) current_len = 1 # Закрыть последнюю серию if current_pair is not None: answer_multirow += current_len * (current_len + 1) // 2 # ----------------------------------------------------------------------------- # Часть 2: считаем количество "правильных" подматриц высотой = 1 # ----------------------------------------------------------------------------- # # Если подматрица состоит из одной строки r и столбцов c1..c2, # то "шахматный" цвет клетки (r, c) есть (r+c) % 2. # Условие "правильности": # - Все столбцы, где (r+c) % 2 = 0, имеют одну и ту же букву A. # - Все столбцы, где (r+c) % 2 = 1, имеют одну и ту же букву B != A. # - В подотрезке [c1..c2] есть хотя бы один c с цветом 0 и хотя бы один c с цветом 1. # - Длина подотрезка >= 2 (иначе невозможно иметь и цвет0, и цвет1 в одной строке). # # Можно решить при помощи "скользящего окна" (двух указателей). def count_one_row_submatrices(row_string, row_index, m): res = 0 # color0_freq[l] -- сколько раз буква l (0..25) встретилась на позициях, где цвет=0 # color1_freq[l] -- где цвет=1 color0_freq = [0]*26 color1_freq = [0]*26 # Число различных букв среди позиций цвета 0 distinct0 = 0 # Число различных букв среди позиций цвета 1 distinct1 = 0 # Сколько всего клеток цвета 0 в текущем окне [left..right] count0 = 0 # Сколько всего клеток цвета 1 count1 = 0 left = 0 for right in range(m): c = row_string[right] letter_id = ord(c) - ord('a') if ((row_index + right) % 2) == 0: # цвет 0 count0 += 1 color0_freq[letter_id] += 1 if color0_freq[letter_id] == 1: distinct0 += 1 else: # цвет 1 count1 += 1 color1_freq[letter_id] += 1 if color1_freq[letter_id] == 1: distinct1 += 1 # "Сжимаем" левую границу, пока подотрезок [left..right] не станет валидным # Критерии валидности: # 1) distinct0 <= 1 # 2) distinct1 <= 1 # 3) count0 > 0 и count1 > 0 (обе "краски" должны быть в отрезке) # 4) если distinct0 == 1 и distinct1 == 1, то единственные буквы не должны совпадать while True: # Проверяем, валиден ли текущий [left..right] if distinct0 <= 1 and distinct1 <= 1 and count0 > 0 and count1 > 0: # Если ровно по 1 букве в каждом цвете, проверим различны ли они if distinct0 == 1 and distinct1 == 1: # Находим какие именно буквы # (так как distinct0==1, среди color0_freq ровно одна буква > 0) # (аналогично для color1_freq) letter0 = -1 for i in range(26): if color0_freq[i] > 0: letter0 = i break letter1 = -1 for i in range(26): if color1_freq[i] > 0: letter1 = i break if letter0 == letter1: # невалидно pass else: # валидно, можно выходить из while break else: # Если distinct0 == 0 или distinct1 == 0, или одна из них больше 1, # либо нет обоих цветов - тоже невалидно pass # Иначе невалидно - будем двигать left if left > right: # Окно пустое, выходим break # Убираем left-элемент c_left = row_string[left] letter_left = ord(c_left) - ord('a') if ((row_index + left) % 2) == 0: # уходящая клетка была цвет0 count0 -= 1 color0_freq[letter_left] -= 1 if color0_freq[letter_left] == 0: distinct0 -= 1 else: # цвет1 count1 -= 1 color1_freq[letter_left] -= 1 if color1_freq[letter_left] == 0: distinct1 -= 1 left += 1 # Теперь [left..right], если он валиден, то все его подотрезки, заканчивающиеся в right # и начинающиеся от left..(right-1) тоже проверять. Нам нужны подотрезки длиной >= 2. length = right - left + 1 if length >= 2: # Все подотрезки, заканчивающиеся в right, начинаются от индексов s, где s >= left # Так что количество таких подотрезков = length-1 (т.е. s = left..(right-1)) # Но добавляем именно length - 1 res += (length - 1) return res answer_singlerow = 0 for r in range(n): answer_singlerow += count_one_row_submatrices(matrix[r], r, m) # Суммарный результат answer = answer_multirow + answer_singlerow print(answer)
Подсчёт для высоты :
col0Letter[c] храним текущую букву для «белых» клеток (цвет 0) в столбце или None, если либо буква ещё не определена, либо уже был конфликт. Аналогично col1Letter[c] для «чёрных» (цвет 1).Подсчёт для высоты :
right, постепенно добавляя столбцы. Если в окне нарушаются условия (например, среди «белых» больше одной возможной буквы), то двигаем левую границу left, убирая лишние столбцы, пока окно снова не станет «валидным».right (после «сжатия» левой границы) количество подотрезков, заканчивающихся на right и длиной , равно .В сумме оба подхода дают искомое число всех «правильных» подматриц.
Итого при код может работать на грани, но при достаточно оптимизированном Python (или PyPy) обычно укладывается в разумные ограничения.
Итог: вышеуказанный скрипт читает входные данные в формате задачи, выводит одно число — количество «правильных» подматриц. В примерах:
Должно получиться 5.text2 2 ab ba
Должно получиться 0.text2 2 aa aa