Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import math
- class SegmentTreeForPrevNext:
- def __init__(self, n_elements: int):
- self.n = n_elements
- self.tree_leaf_start_idx = 1
- while self.tree_leaf_start_idx < self.n:
- self.tree_leaf_start_idx *= 2
- self.tree = [0] * (2 * self.tree_leaf_start_idx)
- def mark_malicious(self, original_idx: int):
- current_tree_node_idx = self.tree_leaf_start_idx + original_idx
- if self.tree[current_tree_node_idx] == 1:
- return
- self.tree[current_tree_node_idx] = 1
- while current_tree_node_idx > 1:
- current_tree_node_idx //= 2
- self.tree[current_tree_node_idx] = self.tree[current_tree_node_idx * 2] + self.tree[current_tree_node_idx * 2 + 1]
- def _find_rightmost_one_recursive(self, current_tree_node_idx: int,
- node_L: int, node_R: int,
- query_L: int, query_R: int) -> int:
- if query_L > query_R or node_L > query_R or node_R < query_L or self.tree[current_tree_node_idx] == 0:
- return -1
- if node_L == node_R:
- return node_L
- mid = (node_L + node_R) // 2
- res_right = self._find_rightmost_one_recursive(2 * current_tree_node_idx + 1, mid + 1, node_R, query_L, query_R)
- if res_right != -1:
- return res_right
- res_left = self._find_rightmost_one_recursive(2 * current_tree_node_idx, node_L, mid, query_L, query_R)
- return res_left
- def find_prev_malicious_site(self, original_idx: int) -> int:
- if original_idx == 0:
- return -1
- return self._find_rightmost_one_recursive(1, 0, self.tree_leaf_start_idx - 1, 0, original_idx - 1)
- def _find_leftmost_one_recursive(self, current_tree_node_idx: int,
- node_L: int, node_R: int,
- query_L: int, query_R: int) -> int:
- if query_L > query_R or node_L > query_R or node_R < query_L or self.tree[current_tree_node_idx] == 0:
- return -1
- if node_L == node_R:
- return node_L
- mid = (node_L + node_R) // 2
- res_left = self._find_leftmost_one_recursive(2 * current_tree_node_idx, node_L, mid, query_L, query_R)
- if res_left != -1:
- return res_left
- res_right = self._find_leftmost_one_recursive(2 * current_tree_node_idx + 1, mid + 1, node_R, query_L, query_R)
- return res_right
- def find_next_malicious_site(self, original_idx: int) -> int:
- if original_idx == self.n - 1:
- return self.n
- res = self._find_leftmost_one_recursive(1, 0, self.tree_leaf_start_idx - 1, original_idx + 1, self.n - 1)
- return res if res != -1 else self.n
- def findMinimumTime(password: str, attackOrder: list[int], m: int) -> int:
- N = len(password)
- if N == 0:
- return 0
- if m == 0:
- return 1
- def count_substrings_from_length(k: int) -> int:
- if k <= 0:
- return 0
- return k * (k + 1) // 2
- seg_tree = SegmentTreeForPrevNext(N)
- current_total_clean_substrings = count_substrings_from_length(N)
- total_possible_substrings = current_total_clean_substrings
- for t, attack_pos_1_indexed in enumerate(attackOrder):
- time_step = t + 1
- attack_idx_0_based = attack_pos_1_indexed - 1
- prev_mal_idx = seg_tree.find_prev_malicious_site(attack_idx_0_based)
- next_mal_idx = seg_tree.find_next_malicious_site(attack_idx_0_based)
- len_old_segment = next_mal_idx - prev_mal_idx - 1
- current_total_clean_substrings -= count_substrings_from_length(len_old_segment)
- len_left_segment = attack_idx_0_based - prev_mal_idx - 1
- current_total_clean_substrings += count_substrings_from_length(len_left_segment)
- len_right_segment = next_mal_idx - attack_idx_0_based - 1
- current_total_clean_substrings += count_substrings_from_length(len_right_segment)
- seg_tree.mark_malicious(attack_idx_0_based)
- num_malicious_substrings = total_possible_substrings - current_total_clean_substrings
- if num_malicious_substrings >= m:
- return time_step
- return -1
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement