結果
| 問題 |
No.252 "良問"(良問とは言っていない (2)
|
| コンテスト | |
| ユーザー |
qwewe
|
| 提出日時 | 2025-05-14 13:23:09 |
| 言語 | PyPy3 (7.3.15) |
| 結果 |
TLE
|
| 実行時間 | - |
| コード長 | 5,451 bytes |
| コンパイル時間 | 367 ms |
| コンパイル使用メモリ | 82,060 KB |
| 実行使用メモリ | 97,064 KB |
| 最終ジャッジ日時 | 2025-05-14 13:25:14 |
| 合計ジャッジ時間 | 6,781 ms |
|
ジャッジサーバーID (参考情報) |
judge4 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | TLE * 1 -- * 6 |
ソースコード
import math
def solve():
S = input()
n = len(S)
patterns = ["good", "problem"]
pattern_masks = [1, 2] # 1 for "good", 2 for "problem"
# Build Aho-Corasick automaton
# Max states roughly sum of lengths of patterns + 1
# good (4), problem (7) -> 4+7+1 = 12 states initially.
# Let's allocate a bit more just in case, e.g., 20.
MAX_AC_STATES = sum(len(p) for p in patterns) + 5
trie = [[0] * 26 for _ in range(MAX_AC_STATES)]
# output_at_state[ac_state] stores the bitmask of patterns ending at this state
output_at_state = [0] * MAX_AC_STATES
failure_link = [0] * MAX_AC_STATES # failure_link[ac_state] is the state to go to on failure
num_ac_states = 1 # state 0 is the root (empty string)
for p_idx, p_str in enumerate(patterns):
curr_node = 0
for char_val in p_str:
char_code = ord(char_val) - ord('a')
if trie[curr_node][char_code] == 0:
trie[curr_node][char_code] = num_ac_states
num_ac_states += 1
curr_node = trie[curr_node][char_code]
output_at_state[curr_node] |= pattern_masks[p_idx]
# Build failure links using BFS
queue = []
for char_code in range(26):
if trie[0][char_code] != 0: # Children of root
queue.append(trie[0][char_code])
# failure_link for children of root is root itself (0)
head = 0
while head < len(queue):
u_node = queue[head]
head += 1
# For each character, find transition from u_node
for char_code in range(26):
v_node = trie[u_node][char_code]
if v_node == 0: # No direct child with this char
continue
# v_node is a direct child of u_node
# To find failure_link[v_node]:
# Start from failure_link[u_node] and try to follow char_code
f_u = failure_link[u_node]
while f_u != 0 and trie[f_u][char_code] == 0:
f_u = failure_link[f_u]
failure_link[v_node] = trie[f_u][char_code]
# Important: Output of a state includes outputs of its failure state
output_at_state[v_node] |= output_at_state[failure_link[v_node]]
queue.append(v_node)
# Precompute goto function for AC (memoized transitions)
# ac_goto[state][char_code] = next_state
ac_goto_memo = [[-1] * 26 for _ in range(num_ac_states)]
def get_ac_next_state(curr_ac_state, char_code):
if ac_goto_memo[curr_ac_state][char_code] != -1:
return ac_goto_memo[curr_ac_state][char_code]
temp_state = curr_ac_state
while temp_state != 0 and trie[temp_state][char_code] == 0:
temp_state = failure_link[temp_state]
res_state = trie[temp_state][char_code]
ac_goto_memo[curr_ac_state][char_code] = res_state
return res_state
# DP state: dp[ac_state][phase] = min_cost
# Phases:
# 0: Before finding "good"
# 1: After "good" found, before "problem" (that's after "good")
# 2: After "good" and then "problem" both found
dp = [[math.inf] * 3 for _ in range(num_ac_states)]
dp[0][0] = 0 # Start at root (state 0), phase 0, cost 0
for k in range(n): # Iterate through characters of S
s_original_char_code = ord(S[k]) - ord('a')
new_dp = [[math.inf] * 3 for _ in range(num_ac_states)]
for prev_ac_state in range(num_ac_states):
for prev_phase in range(3):
if dp[prev_ac_state][prev_phase] == math.inf:
continue
for char_code_to_place in range(26): # Try all 'a' through 'z'
cost_for_char = 0 if char_code_to_place == s_original_char_code else 1
current_ac_state = get_ac_next_state(prev_ac_state, char_code_to_place)
matches = output_at_state[current_ac_state]
current_phase = prev_phase
# Update phase based on matches
# Order matters: if "good" matched, phase can go 0->1. Then if "problem" also matched, phase can go 1->2.
if (matches & pattern_masks[0]): # "good" matched
if current_phase == 0:
current_phase = 1
if (matches & pattern_masks[1]): # "problem" matched
if current_phase == 0: # Problem found before good, or simultaneously but "good" didn't set phase to 1
# This path is invalid.
continue # Skip updating dp for this invalid transition
elif current_phase == 1:
current_phase = 2
new_dp[current_ac_state][current_phase] = min(
new_dp[current_ac_state][current_phase],
dp[prev_ac_state][prev_phase] + cost_for_char
)
dp = new_dp
min_total_cost = math.inf
for final_ac_state in range(num_ac_states):
min_total_cost = min(min_total_cost, dp[final_ac_state][2])
return min_total_cost if min_total_cost != math.inf else -1 # Should always be possible
T = int(input())
for _ in range(T):
print(solve())
qwewe