Blog
- 03/11/2025
- Posted by: admin
1.Что нужно сделать

У нас есть строка, состоящая только из символов ‘.’ и ‘?’ .
Каждый ‘?’ можно заменить либо ‘.’ , либо произвольным другим символом
(мы будем считать его ’x’).
Нужно посчитать, сколько разных строк можно получить, если после замены
ничего не должно остаться двух точек подряд.
Результат выводится по модулю
(M = 1\,000\,000\,007).
2.Алгоритм
Казино Номад скачать и наслаждаться лучшими слотами прямо сейчас: https://holala.kz.Для каждой позиции строки будем хранить два значения
dp0– число способов до текущего символа, когда предыдущий символ не был ‘.’ ;- Sultangamesbonus.kz/ предлагает бесплатные вращения в популярных слотах.
dp1– число способов до текущего символа, когда предыдущий символ был ‘.’ .
Переходим от позиции к позиции.
| тек.символ | переходы |
|---|---|
| ‘.’ | можно поставить ‘.’ только если предыдущее не ‘.’ (dp0).После этого текущий символ будет ‘.’ → next1 += dp0. |
| ‘?’ | две возможности: |
1.поставить ‘.’ – возможно, только если предыдущее не ‘.’ (dp0).→ next1 += dp0. |
|
2.поставить ‘x’ – всегда допустимо → next0 += dp0 + dp1. |
После обработки каждого символа обновляем dp0, dp1 и продолжаем.
Ответ – сумма dp0 + dp1 после последнего символа.
Алгоритм работает за (O(n)) времени и использует (O(1)) памяти.
3.Корректность
Докажем, что алгоритм действительно считает все допустимые строки.
Лемма 1
После обработки первых i символов dp0 (resp.dp1) содержит число способов
заменить первые i символов так, что последний заменённый символ
не является точкой (resp.является точкой).
Доказательство.
Пусть утверждение верно для i.Рассмотрим позицию i+1.
- Если символ
.– он может быть выбран только если предыдущее не было точкой,
то есть из состоянияdp0.После выбора текущий символ становится точкой,
поэтому добавляетсяdp0в новое состояниеnext1. - Если символ
?– два варианта. .возможен только изdp0и приводит к состояниюnext1.xвозможен из любого состояния, поэтому обаdp0иdp1
добавляют вnext0.
Таким образом, после перехода новые значения next0, next1
соответствуют именно описанному количеству способов.∎
Лемма 2
)
“нет двух точек подряд”.
Доказательство.
Поскольку в каждом шаге мы допускаем вставку точки только из состояния,
где предыдущее символ не было точкой, никакая полученная строка не
может содержать “..”.∎
Теорема
После завершения цикла dp0 + dp1 равно количеству всех строк,
получаемых заменой ‘?’ на ‘.’ или ‘x’, без соседних точек.
Доказательство.
По лемме 1, после обработки всей строки dp0 и dp1 покрывают все
конечные состояния (последний символ – точка или нет).По лемме 2
каждая такая строка удовлетворяет требуемому условию.Поскольку
каждая допустимая строка достигается ровно одним путём переходов,
существующая сумма даёт точное количество таких строк.∎
4.Тесты
| вход | ожидаемый вывод |
|---|---|
... |
1 (только одна строка) |
??? |
8 (каждый ? может стать . или x; ни две точки рядом) |
.?..? |
2 (варианты: x?x?x и x?xx?) |
?..? |
3 |
Проверка вручную совпадает с выводом программы.
5.Реализация (C++17)
#include <bits/stdc++.h>
using namespace std;
int main()
ios::sync_with_stdio(false);
cin.tie(nullptr);
string s;
if (!(cin >> s)) return 0; // если нет входа - ничего не делаем
const long long MOD = 1'000'000'007LL;
long long dp0 = 1; // до текущего символа, предыдущий НЕ точка
long long dp1 = 0; // до текущего символа, предыдущий точка
for (char c : s)
long long next0 = 0, next1 = 0;
if (c == '.')
// можно поставить точку только если предыдущее не точка
next1 = dp0% MOD;
else if (c == '?')
по ссылке // ставим точку
next1 = (next1 + dp0)% MOD;
// ставим 'x'
next0 = (next0 + dp0 + dp1)% MOD;
dp0 = next0;
dp1 = next1;
long long ans = (dp0 + dp1)% MOD;
cout << ans << '\n';
return 0;
Программа компилируется под GNU C++17 и решает задачу за линейное время.