結果
問題 |
No.962 LCPs
|
ユーザー |
![]() |
提出日時 | 2025-03-20 20:39:31 |
言語 | PyPy3 (7.3.15) |
結果 |
AC
|
実行時間 | 258 ms / 2,000 ms |
コード長 | 4,957 bytes |
コンパイル時間 | 200 ms |
コンパイル使用メモリ | 82,424 KB |
実行使用メモリ | 143,164 KB |
最終ジャッジ日時 | 2025-03-20 20:39:52 |
合計ジャッジ時間 | 8,228 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge4 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 2 |
other | AC * 64 |
ソースコード
def main(): import sys input = sys.stdin.read data = input().split() N = int(data[0]) S = data[1:N+1] len_list = [len(s) for s in S] if N == 0: print(0) return # Precompute LCP for consecutive pairs lcp_list = [] for i in range(N-1): a = S[i] b = S[i+1] min_len = min(len(a), len(b)) lcp = 0 while lcp < min_len and a[lcp] == b[lcp]: lcp += 1 lcp_list.append(lcp) events = [] for i in range(N): events.append((-len_list[i], 'element', i)) # Use negative to reverse sort for i in range(N-1): events.append((-lcp_list[i], 'pair', i)) # Sort events. For the same m, process elements before pairs to enable elements first events.sort() parent = list(range(N)) left = list(range(N)) right = list(range(N)) enabled_elements = [False] * N enabled_pairs = [False] * (N-1) current_sum = 0 answer = 0 prev_m = None def find(u): while parent[u] != u: parent[u] = parent[parent[u]] u = parent[u] return u for event in events: m_neg, typ, idx = event m = -m_neg if prev_m is not None: delta = prev_m - m answer += current_sum * delta else: delta = 0 prev_m = m if typ == 'element': i = idx if enabled_elements[i]: continue enabled_elements[i] = True K = 1 contribute = K * (K + 1) * (K + 2) // 6 current_sum += contribute # Check left neighbor if i > 0 and enabled_elements[i-1] and enabled_pairs[i-1]: left_root = find(i-1) current_root = find(i) if left_root != current_root: left_left = left[left_root] left_right = right[left_root] current_left = left[current_root] current_right = right[current_root] if left_right + 1 == current_left: K1 = left_right - left_left + 1 K2 = current_right - current_left + 1 current_sum -= K1 * (K1+1) * (K1+2) // 6 current_sum -= K2 * (K2+1) * (K2+2) // 6 parent[current_root] = left_root left[left_root] = left_left right[left_root] = current_right new_K = right[left_root] - left[left_root] + 1 current_sum += new_K * (new_K + 1) * (new_K + 2) // 6 # Check right neighbor if i < N-1 and enabled_elements[i+1] and enabled_pairs[i]: right_root = find(i+1) current_root = find(i) if right_root != current_root: current_left = left[current_root] current_right = right[current_root] right_left = left[right_root] right_right = right[right_root] if current_right + 1 == right_left: K1 = current_right - current_left + 1 K2 = right_right - right_left + 1 current_sum -= K1 * (K1+1) * (K1+2) // 6 current_sum -= K2 * (K2+1) * (K2+2) // 6 parent[right_root] = current_root right[current_root] = right_right new_K = right[current_root] - left[current_root] + 1 current_sum += new_K * (new_K + 1) * (new_K + 2) // 6 else: # pair event i = idx if enabled_pairs[i]: continue enabled_pairs[i] = True if enabled_elements[i] and enabled_elements[i+1]: # Try to merge the segments root1 = find(i) root2 = find(i+1) if root1 == root2: continue left1 = left[root1] right1 = right[root1] left2 = left[root2] right2 = right[root2] if right1 + 1 == left2: K1 = right1 - left1 + 1 K2 = right2 - left2 + 1 current_sum -= K1 * (K1+1) * (K1+2) //6 current_sum -= K2 * (K2+1) * (K2+2) //6 parent[root2] = root1 left[root1] = left1 right[root1] = right2 new_K = right[root1] - left[root1] +1 current_sum += new_K * (new_K+1) * (new_K+2) //6 # Add remaining m=prev_m down to 0 if prev_m is not None: answer += current_sum * prev_m print(answer) if __name__ == '__main__': main()