10. Вопрос 24. Два указателя и скользящее окно. Шаблон 4 — "РОВНО K раз", считаем КОЛИЧЕСТВО подстрок



Шаблон 4 — "РОВНО K раз", считаем КОЛИЧЕСТВО подстрок

Задача-пример

Сколько подстрок содержат букву X ровно 2 раза?

Строка: A X X A

Принцип

Количество(ровно K) = Количество(не более K) − Количество(не более K-1)
Пошаговый разбор

Сначала посчитаем подстроки с не более 2 букв X:

Строка: A X X A
        0 1 2 3

Для "не более K" считаем: на каждом шаге все подстроки, заканчивающиеся в right.

right=0: окно [0,0]="A", подстроки: "A" → +1
right=1: окно [0,1]="AX", подстроки: "AX", "X" → +2
right=2: окно [0,2]="AXX", подстроки: "AXX", "XX", "X" → +3
right=3: окно [0,3]="AXXA", подстроки: "AXXA", "XXA", "XA", "A" → +4

Итого "не более 2": 1 + 2 + 3 + 4 = 10

Теперь посчитаем подстроки с не более 1 буквы X:

right=0: окно [0,0]="A" → +1
right=1: окно [0,1]="AX" → +2
right=2: count=2 > 1, сужаем до [2,2]="X" → +1
right=3: окно [2,3]="XA" → +2

Итого "не более 1": 1 + 2 + 1 + 2 = 6

Ответ
Ровно 2 = (не более 2) − (не более 1) = 10 − 6 = 4

Проверим: подстроки с ровно 2 буквами X:

  • "AXX" (позиции 0-2)
  • "XX" (позиции 1-2)
  • "XXA" (позиции 1-3)
  • "AXXA" (позиции 0-3)

Код

def count_exactly_k(s, k):
    def count_at_most(k):
        if k < 0:
            return 0
        left = 0
        count_x = 0
        result = 0
        
        for right in range(len(s)):
            if s[right] == 'X':
                count_x += 1
            
            while count_x > k:
                if s[left] == 'X':
                    count_x -= 1
                left += 1
            
            result += right - left + 1  # все подстроки [left..right], [left+1..right], ...
        
        return result
    
    return count_at_most(k) - count_at_most(k - 1)


Ключевое правило Шаблона 4

┌──────────────────────────────────────────────────┐
│  exactly(K) = atMost(K) − atMost(K − 1)          │
│  На каждом шаге: result += right − left + 1      │
└──────────────────────────────────────────────────┘

Шаблон 4 (atMost(K) - atMost(K-1)) — это скорее олимпиадная техника.
На ЕГЭ такие задачи пока не встречались.
Но знать её полезно, потому что:
  • Может появиться в будущем
  • Помогает глубже понять связь между "не более K" и "ровно K"

time 1000 ms
memory 256 Mb

Комментарий учителя