We have a string that consists only of the characters ‘.’ and ‘?’
‘.’ is a fixed symbol, ‘?’ can be replaced by either ‘.’ or ‘#’.
After all replacements the string must not contain two consecutive ‘#’.
Участвуйте в турнирах онлайн рулетки и побеждайте крупные суммы: https://dd3ca.kz. For a string of length n let
dp[i][0] - number of valid ways for the prefix of length i that ends with ‘.’
dp[i][1] - number of valid ways for the prefix of length i that ends with ‘#’
Сайт онлайн рулетка предлагает лучшие условия для онлайн рулетки. Transition for the i‑th character (c = s[i‑1]):

| c | dp[i][0] | dp[i][1] |
|---|---|---|
| ‘.’ | dp[i‑1][0] + dp[i‑1][1] | 0 |
| ‘#’ | 0 | dp[i‑1][0] |
| ‘?’ | dp[i‑1][0] + dp[i‑1][1] | dp[i‑1][0] |
All computations are performed modulo
(M = 1\,000\,000\,007).
The answer for the whole string is
(dp[n][0] + dp[n][1]) mod M.
Algorithm
read string s
n ← length(s)
dp0 ← 1 // empty prefix ends with '.'
dp1 ← 0
for each character c in s
if c == '.'
new0 ← (dp0 + dp1) mod M
new1 ← 0
else if c == '#'
new0 ← 0
new1 ← dp0
else // c == '?'
new0 ← (dp0 + dp1) mod M
new1 ← dp0
dp0 ← new0
dp1 ← new1
output (dp0 + dp1) mod M
Correctness Proof
We prove that the algorithm outputs the number of ways to replace every
‘?’ by ‘.’ or ‘#’ such that no two ‘#’ are adjacent.
Lemma 1
For every i (0 ≤ i ≤ n) after processing the first i characters,
dp0 equals the number of valid fillings of the prefix s[0…i‑1]
ending with ‘.’, and dp1 equals the number ending with ‘#’.
Proof.
Base case i = 0: the empty prefix ends with a virtual ‘.’,
so dp0 = 1, dp1 = 0.
Induction step: assume the lemma holds for i‑1.
Consider character c = s[i‑1].
-
If
c = '.'the current position must be ‘.’.
Any valid filling of the firsti‑1characters (ending with ‘.’ or ‘#’)
can be extended by ‘.’, givingnew0 = dp0 + dp1.
No filling can end with ‘#’, sonew1 = 0. - Сайт онлайн рулетка предлагает лучшие условия для онлайн рулетки.
If
c = '#'the current position must be ‘#’.
A valid filling can extend only a prefix that ends with ‘.’,
otherwise two consecutive ‘#’ would appear.
Thusnew1 = dp0andnew0 = 0. -
If
c = '?'we can choose ‘.’ or ‘#’.
For ‘.’ the reasoning is the same as the first case, producing
new0 = dp0 + dp1.
For ‘#’ we again need a preceding ‘.’, givingnew1 = dp0.
In each case the transition sets dp0,new0 and dp1,new1
exactly to the numbers described in the lemma.∎
Lemma 2
After the loop finishes (i = n) the sum dp0 + dp1
equals the total number of valid completions of the whole string.
Proof.
By Lemma 1, dp0 counts all valid fillings that end with ‘.’,
and dp1 counts all that end with ‘#’.
Every valid filling ends with either ‘.’ or ‘#’, and the two sets are
disjoint. Therefore their sum is precisely the total number of
valid completions.∎
Theorem
The algorithm outputs the number of ways to replace every ‘?’ in the
input string with ‘.’ or ‘#’ so that no two ‘#’ are adjacent.
Proof.
By Lemma 2 the value printed by the algorithm equals the total
number of valid completions. Hence the algorithm is correct.∎
Complexity Analysis
The algorithm scans the string once, проверьте это performing O(1) work per character.
Time complexity: O(n)
Memory usage: O(1) (only a few integer variables)
Reference Implementation (Python 3)
import sys
MOD = 1_000_000_007
def solve() -> None:
s = sys.stdin.readline().strip()
dp0, dp1 = 1, 0 # empty prefix ends with '.'
for ch in s:
if ch == '.':
new0 = (dp0 + dp1)% MOD
new1 = 0
elif ch == '#':
new0 = 0
new1 = dp0
else: # ch == '?'
new0 = (dp0 + dp1)% MOD
new1 = dp0
dp0, dp1 = new0, new1
print((dp0 + dp1)% MOD)
if __name__ == "__main__":
solve()
The program follows exactly the algorithm proven correct above
and conforms to the required time and memory limits.

