Untitled
unknown
python
2 years ago
3.7 kB
5
Indexable
from collections import namedtuple
from typing import List
Data = namedtuple('Data', ['char', 'cnt'])
LEFT = 'LEFT'
RIGHT = 'RIGHT'
def count_substring(a):
return a * (a + 1) // 2
memo = {}
def dp(data: List[Data], seen: List[int], idx: int, direction: str):
inputs = (idx, direction)
if inputs in memo:
return memo[inputs]
m = len(data)
res = 0
curr_idx = seen[idx]
if direction == LEFT:
if idx == len(seen) - 1:
for j in range(curr_idx + 1, len(data)):
res += count_substring(data[j].cnt)
else:
next_idx = seen[idx+1]
for j in range(curr_idx + 1, next_idx - 1):
res += count_substring(data[j].cnt)
res += max(count_substring(data[next_idx-1].cnt) + dp(data, seen, idx + 1, RIGHT),
count_substring(data[next_idx-1].cnt + data[next_idx].cnt) + dp(data, seen, idx + 1, LEFT))
else:
# direction == RIGHT
if idx == len(seen) - 1:
res += count_substring(data[curr_idx].cnt + data[curr_idx+1].cnt)
for j in range(curr_idx + 2, len(data)):
res += count_substring(data[j].cnt)
else:
next_idx = seen[idx+1]
if next_idx - curr_idx == 2:
res += max(count_substring(data[curr_idx].cnt + data[curr_idx+1].cnt) + dp(data, seen, idx + 1, RIGHT),
count_substring(data[curr_idx].cnt + data[curr_idx+1].cnt + data[next_idx].cnt) + dp(data, seen, idx + 1, LEFT))
else:
res += count_substring(data[curr_idx].cnt +
data[curr_idx+1].cnt)
for j in range(curr_idx + 2, next_idx - 1):
res += count_substring(data[j].cnt)
res += max(count_substring(data[next_idx-1].cnt) + dp(data, seen, idx + 1, RIGHT),
count_substring(data[next_idx-1].cnt + data[next_idx].cnt) + dp(data, seen, idx + 1, LEFT))
memo[inputs] = res
return res
def solve(color: str):
# pre-processing
data = []
prev = None
cnt = 0
for i, v in enumerate(color):
if v == prev:
cnt += 1
else:
data.append(Data(prev, cnt))
prev = v
cnt = 1
data.append(Data(color[-1], cnt))
data.pop(0)
# print(f'data {data}')
# head and tail
if len(data) == 1:
return count_substring(data[0].cnt)
if data[0].char == '.':
data[1] = Data(data[1].char, data[0].cnt + data[1].cnt)
data.pop(0)
if data[-1][0] == '.':
data[-2] = Data(data[-2].char, data[-1].cnt + data[-2].cnt)
data.pop()
# merge
for i in range(1, len(data) - 1):
if data[i].char == '.' and data[i-1] and data[i-1].char == data[i+1].char:
data[i+1] = Data(data[i+1].char,
data[i-1].cnt + data[i].cnt + data[i+1].cnt)
data[i] = None
data[i-1] = None
data = [x for x in data if x is not None]
print(f'data {data}')
m = len(data)
# dp
memo = [0] * m
seen = []
for i in range(len(data)):
if data[i].char == '.':
seen.append(i)
res = 0
for i in range(seen[0] - 1):
res += count_substring(data[i].cnt)
return res + max(count_substring(data[seen[0]-1].cnt) + dp(data, seen, 0, RIGHT),
count_substring(data[seen[0]-1].cnt + data[seen[0]].cnt) + dp(data, seen, 0, LEFT))
color = '.bb.a.aa.'
print(f'solve {color}: {solve(color)}')
print(f'memo {memo}')
Editor is loading...
Leave a Comment