<p>You are given a <strong>0-indexed</strong> binary string <code>s</code> which represents the types of buildings along a street where:</p>

<ul>
	<li><code>s[i] = &#39;0&#39;</code> denotes that the <code>i<sup>th</sup></code> building is an office and</li>
	<li><code>s[i] = &#39;1&#39;</code> denotes that the <code>i<sup>th</sup></code> building is a restaurant.</li>
</ul>

<p>As a city official, you would like to <strong>select</strong> 3 buildings for random inspection. However, to ensure variety, <strong>no two consecutive</strong> buildings out of the <strong>selected</strong> buildings can be of the same type.</p>

<ul>
	<li>For example, given <code>s = &quot;0<u><strong>0</strong></u>1<u><strong>1</strong></u>0<u><strong>1</strong></u>&quot;</code>, we cannot select the <code>1<sup>st</sup></code>, <code>3<sup>rd</sup></code>, and <code>5<sup>th</sup></code> buildings as that would form <code>&quot;0<strong><u>11</u></strong>&quot;</code> which is <strong>not</strong> allowed due to having two consecutive buildings of the same type.</li>
</ul>

<p>Return <em>the <b>number of valid ways</b> to select 3 buildings.</em></p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

<pre>
<strong>Input:</strong> s = &quot;001101&quot;
<strong>Output:</strong> 6
<strong>Explanation:</strong> 
The following sets of indices selected are valid:
- [0,2,4] from &quot;<u><strong>0</strong></u>0<strong><u>1</u></strong>1<strong><u>0</u></strong>1&quot; forms &quot;010&quot;
- [0,3,4] from &quot;<u><strong>0</strong></u>01<u><strong>10</strong></u>1&quot; forms &quot;010&quot;
- [1,2,4] from &quot;0<u><strong>01</strong></u>1<u><strong>0</strong></u>1&quot; forms &quot;010&quot;
- [1,3,4] from &quot;0<u><strong>0</strong></u>1<u><strong>10</strong></u>1&quot; forms &quot;010&quot;
- [2,4,5] from &quot;00<u><strong>1</strong></u>1<u><strong>01</strong></u>&quot; forms &quot;101&quot;
- [3,4,5] from &quot;001<u><strong>101</strong></u>&quot; forms &quot;101&quot;
No other selection is valid. Thus, there are 6 total ways.
</pre>

<p><strong class="example">Example 2:</strong></p>

<pre>
<strong>Input:</strong> s = &quot;11100&quot;
<strong>Output:</strong> 0
<strong>Explanation:</strong> It can be shown that there are no valid selections.
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>3 &lt;= s.length &lt;= 10<sup>5</sup></code></li>
	<li><code>s[i]</code> is either <code>&#39;0&#39;</code> or <code>&#39;1&#39;</code>.</li>
</ul>

class Solution:
    def numberOfWays(self, s: str) -> int:
        arr_s = []
        arr_cnt = []
        char_prev = None
        for char in s:
            if not char_prev:
                arr_s.append(char)
                arr_cnt.append(1)
                char_prev = char
            else:
                if char == char_prev:
                    arr_cnt[-1] += 1
                else:
                    arr_s.append(char)
                    arr_cnt.append(1)
                    char_prev = char
        # print(f'arr_s: {arr_s}')
        # print(f'arr_cnt: {arr_cnt}')

        n = len(arr_cnt)
        if n < 3:
            return 0

        n_zeros = sum([v[1] for v in zip(arr_s,arr_cnt) if v[0] == '0'])
        n_ones = sum([v[1] for v in zip(arr_s,arr_cnt) if v[0] == '1'])
        # print(f'n_zeros: {n_zeros}, n_ones: {n_ones}.')

        arr_cnt_cum = arr_cnt.copy()
        for i in range(n-3, -1, -2):
            arr_cnt_cum[i] += arr_cnt_cum[i+2]
        for i in range(n-4, -1, -2):
            arr_cnt_cum[i] += arr_cnt_cum[i+2]
        # print(f'arr_cnt_cum: {arr_cnt_cum}')

        diag = [0] * n
        for i in range(1,n-1):
            diag[i] = arr_cnt[i] * arr_cnt_cum[i+1]
        # print(f'diag: {diag}')

        arr_cnt_cum_cum = diag.copy()
        for i in range(n-3, 0, -1):
            arr_cnt_cum_cum[i] += arr_cnt_cum_cum[i+2]
        # print(f'arr_cnt_cum_cum: {arr_cnt_cum_cum}')

        total = 0
        for i in range(n-2):
            total += arr_cnt[i] * arr_cnt_cum_cum[i+1]

        return int(total)





# # DP - TLE
# class Solution:
#     def numberOfWays(self, s: str) -> int:
#         self.s = s
#         self.n = len(s)
#         self.dp = defaultdict(int)
#         total = 0
#         for i in range(self.n):
#             total += self.countWays(-1, i, 1)
#         return total

#     def countWays(self, i_prev: int, i_current: int, total: int):
#         if i_prev >= 0:
#             if self.s[i_prev] == self.s[i_current]:
#                 return 0
#             elif f'{i_current}_{total}' in self.dp:
#                 return self.dp[f'{i_current}_{total}']
#             elif total == 3:
#                 return 1
#             elif i_current == self.n - 1:
#                 return 0
#         self.dp[f'{i_current}_{total}'] = 0
#         for i_next in range(i_current+1, self.n):
#             self.dp[f'{i_current}_{total}'] += self.countWays(i_current, i_next, total+1)
#         return self.dp[f'{i_current}_{total}']
        
        
524