結果

問題 No.348 カゴメカゴメ
ユーザー qwewe
提出日時 2025-05-14 13:19:20
言語 PyPy3
(7.3.15)
結果
WA  
実行時間 -
コード長 14,815 bytes
コンパイル時間 457 ms
コンパイル使用メモリ 82,652 KB
実行使用メモリ 326,884 KB
最終ジャッジ日時 2025-05-14 13:20:34
合計ジャッジ時間 16,838 ms
ジャッジサーバーID
(参考情報)
judge5 / judge2
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 23 WA * 30
権限があれば一括ダウンロードができます

ソースコード

diff #

import sys

# Set recursion depth limit. This is necessary for deep hierarchies potentially formed by nested rings.
# The exact required depth is hard to predict, so a reasonably large value is chosen.
# If this value is too high for the system or contest environment, it might need adjustment.
try:
    # Attempt to set a high recursion depth suitable for large grids (up to 1000x1000)
    sys.setrecursionlimit(2000 * 1000) # Target potentially deep structures. Maybe too high for some systems.
except OverflowError:
     # If the system limits prevent setting a very high value, fallback to smaller but still large values.
    try:
        sys.setrecursionlimit(30000) 
    except OverflowError:
        try:
            sys.setrecursionlimit(20000) 
        except OverflowError:
            sys.setrecursionlimit(10000) # A common safe upper value in competitive programming


def solve():
    N, M = map(int, sys.stdin.readline().split())
    grid = [sys.stdin.readline().strip() for _ in range(N)]

    # Pad the grid with '.' boundary. This simplifies boundary condition checks
    # and helps define the exterior region consistently.
    padded_N = N + 2
    padded_M = M + 2
    padded_grid = [['.' for _ in range(padded_M)] for _ in range(padded_N)]
    
    x_cells = [] # Store coordinates of all 'x' cells for efficient iteration
    for r in range(N):
        for c in range(M):
            padded_grid[r+1][c+1] = grid[r][c]
            if grid[r][c] == 'x':
                x_cells.append((r+1, c+1)) # Use padded coordinates (1-based indexing effectively)

    # If there are no 'x' cells, the maximum strength is 0.
    if not x_cells:
        print(0)
        return

    # --- Step 1: Identify all rings and their strengths ---
    visited_x = [[False for _ in range(padded_M)] for _ in range(padded_N)] # Track visited 'x' cells during tracing
    rings = [] # List to store coordinates of cells for each ring
    ring_strengths = [] # List to store the strength (number of 'x's) of each ring
    # cell_to_ring_id = [[-1 for _ in range(padded_M)] for _ in range(padded_N)] # Optional: Map cell coord to its ring ID
    ring_idx_counter = 0 # Assign a unique ID (0, 1, 2, ...) to each ring

    # Define 8-connectivity directions (dx, dy) for neighbors
    dr = [-1, -1, -1, 0, 0, 1, 1, 1]
    dc = [-1, 0, 1, -1, 1, -1, 0, 1]

    for start_r, start_c in x_cells:
        if not visited_x[start_r][start_c]: # If this 'x' cell hasn't been visited, it's part of a new ring
            
            current_ring_coords = [] # Store coordinates for the current ring being traced
            
            # Trace the ring using iterative approach. Problem guarantees each 'x' has exactly two 'x' neighbors.
            curr_r, curr_c = start_r, start_c
            prev_r, prev_c = -1, -1 # Track previous cell to avoid backtracking immediately

            # Find the first neighbor to start the walk along the ring
            initial_neighbor_found = False
            for i in range(8):
                 nr, nc = curr_r + dr[i], curr_c + dc[i]
                 # Check bounds and if neighbor is 'x'
                 if 0 <= nr < padded_N and 0 <= nc < padded_M and padded_grid[nr][nc] == 'x':
                     prev_r, prev_c = curr_r, curr_c # Update previous cell tracker
                     curr_r, curr_c = nr, nc # Move to the neighbor
                     initial_neighbor_found = True
                     break
            
            if not initial_neighbor_found: continue # Should not happen given problem constraints

            # Add the starting cell to the ring path and mark as visited
            current_ring_coords.append((start_r, start_c))
            visited_x[start_r][start_c] = True
            # cell_to_ring_id[start_r][start_c] = ring_idx_counter

            # Continue tracing the ring until we return to the start cell
            while not (curr_r == start_r and curr_c == start_c):
                 # Add current cell to path and mark visited
                 current_ring_coords.append((curr_r, curr_c))
                 visited_x[curr_r][curr_c] = True
                 # cell_to_ring_id[curr_r][curr_c] = ring_idx_counter
                 
                 # Find the next neighbor in the ring path (must be 'x' and not the previous cell)
                 next_found = False
                 for i in range(8):
                    next_r, next_c = curr_r + dr[i], curr_c + dc[i]
                    # Check bounds and cell type
                    if not (0 <= next_r < padded_N and 0 <= next_c < padded_M): continue
                    if padded_grid[next_r][next_c] != 'x': continue
                    # Ensure it's not the cell we just came from
                    if next_r == prev_r and next_c == prev_c: continue
                    
                    # Move to the next cell
                    prev_r, prev_c = curr_r, curr_c
                    curr_r, curr_c = next_r, next_c
                    next_found = True
                    break # Found the unique next cell in path
            
            # Store the completed ring and its strength
            rings.append(current_ring_coords)
            ring_strengths.append(len(current_ring_coords))
            ring_idx_counter += 1
    
    num_rings = len(rings)
    # If somehow no rings were found (e.g. invalid input structures, though problem guarantees valid ones)
    if num_rings == 0:
        print(0)
        return

    # --- Step 2: Identify connected components of '.' cells ---
    component_id = [[-1 for _ in range(padded_M)] for _ in range(padded_N)] # Assign component ID to each '.' cell
    comp_idx_counter = 0 # Counter for component IDs
    
    # Use BFS to find connected components. Start with Component 0 (C0), the exterior region.
    q_bfs = [(0,0)] # Start BFS from a boundary cell (0,0) guaranteed to be '.' due to padding
    component_id[0][0] = comp_idx_counter
    head_bfs = 0
    while head_bfs < len(q_bfs):
        r, c = q_bfs[head_bfs]; head_bfs += 1
        # Explore 4-direction neighbors
        for dr_4, dc_4 in [(0,1), (0,-1), (1,0), (-1,0)]:
            nr, nc = r + dr_4, c + dc_4
            # Check bounds, if it's '.' cell, and if unvisited
            if 0 <= nr < padded_N and 0 <= nc < padded_M and padded_grid[nr][nc] == '.' and component_id[nr][nc] == -1:
                component_id[nr][nc] = comp_idx_counter
                q_bfs.append((nr, nc))
    comp_idx_counter += 1 # Increment for next component ID

    # Find any remaining interior components
    for r in range(padded_N):
        for c in range(padded_M):
            if padded_grid[r][c] == '.' and component_id[r][c] == -1: # Found an unvisited '.' cell
                 # Start BFS for new component
                 q_bfs = [(r, c)]; component_id[r][c] = comp_idx_counter; head_bfs = 0
                 while head_bfs < len(q_bfs):
                     curr_r, curr_c = q_bfs[head_bfs]; head_bfs += 1
                     for dr_4, dc_4 in [(0,1), (0,-1), (1,0), (-1,0)]:
                         nr, nc = curr_r + dr_4, curr_c + dc_4
                         if 0 <= nr < padded_N and 0 <= nc < padded_M and padded_grid[nr][nc] == '.' and component_id[nr][nc] == -1:
                             component_id[nr][nc] = comp_idx_counter
                             q_bfs.append((nr, nc))
                 comp_idx_counter += 1 # Increment for next component ID

    num_components = comp_idx_counter # Total number of '.' components
    initial_num_components = num_components # Store original count before potentially adding dummy components

    # --- Step 3: Build Component Graph and Ring Hierarchy ---

    # Map rings to the pair of components they separate & Build Component Graph Adjacency List
    ring_to_components = {} # Stores pair [comp_id1, comp_id2] for each ring_id
    adjComp = {} # Adjacency list for component graph: comp_id -> list of (neighbor_comp_id, ring_id)
    for comp_id in range(num_components): adjComp[comp_id] = [] # Initialize empty lists for all components

    for ring_id in range(num_rings):
        adj_comps = set() # Collect unique component IDs adjacent to this ring
        # Check 4-neighbors of each 'x' in the ring
        for r, c in rings[ring_id]:
             for dr_4, dc_4 in [(0,1), (0,-1), (1,0), (-1,0)]:
                 nr, nc = r + dr_4, c + dc_4
                 if 0 <= nr < padded_N and 0 <= nc < padded_M and padded_grid[nr][nc] == '.':
                     comp_id_neighbor = component_id[nr][nc]
                     if comp_id_neighbor != -1: # Make sure it's a valid component ID
                       adj_comps.add(comp_id_neighbor)
        
        # Process based on number of adjacent components found
        if len(adj_comps) == 2: # Standard case: ring separates two components
             c1, c2 = list(adj_comps)
             ring_to_components[ring_id] = [c1, c2]
             # Add edges to component graph adjacency list
             if c1 not in adjComp: adjComp[c1] = [] # Ensure list exists
             if c2 not in adjComp: adjComp[c2] = []
             adjComp[c1].append((c2, ring_id))
             adjComp[c2].append((c1, ring_id))
        elif len(adj_comps) == 1: # Special case: Ring adjacent only to one component
             comp = list(adj_comps)[0]
             if comp == 0: # If that component is C0 (exterior)
                 # Create a dummy component to represent the "inside" region for structural consistency
                 dummy_comp_id = num_components 
                 ring_to_components[ring_id] = [0, dummy_comp_id]
                 
                 # Add edge between C0 and the dummy component in the graph
                 if 0 not in adjComp: adjComp[0] = [] # Should already exist but check just in case
                 adjComp[0].append((dummy_comp_id, ring_id))
                 # Also add dummy component node and back edge
                 if dummy_comp_id not in adjComp: adjComp[dummy_comp_id] = []
                 adjComp[dummy_comp_id].append((0, ring_id))
                 
                 num_components += 1 # Increment total component count for this new dummy node
             # Else: adjacent to only one *interior* component? This case is unexpected based on problem statement.

    # Determine parent-child relationships between components via BFS from C0
    ParentComp = [-1] * num_components # Store parent component ID for each component
    CompEdgeRing = {} # Map tuple (parent_comp, child_comp) -> ring_id separating them

    q_bfs = [0]; visited_comp = {0}; ParentComp[0] = -2 # Mark C0 as root (-2 to distinguish from no parent -1)
    head_bfs = 0
    while head_bfs < len(q_bfs):
        curr_comp = q_bfs[head_bfs]; head_bfs += 1
        # Explore neighbors in the component graph
        if curr_comp in adjComp:
            for neighbor_comp, ring_id in adjComp[curr_comp]:
                if neighbor_comp not in visited_comp:
                    visited_comp.add(neighbor_comp)
                    ParentComp[neighbor_comp] = curr_comp # Record parent
                    # Store the ring associated with the directed edge (parent -> child)
                    CompEdgeRing[(curr_comp, neighbor_comp)] = ring_id 
                    q_bfs.append(neighbor_comp) # Add child to queue

    # Construct the Ring Hierarchy Tree using an adjacency list
    adjRing = [[] for _ in range(num_rings + 1)] # Adjacency list for rings, +1 for Virtual Root
    VIRTUAL_ROOT = num_rings # Use index `num_rings` as the virtual root ID

    for ring_id in range(num_rings):
        if ring_id not in ring_to_components: continue # Skip if ring data missing

        c1, c2 = ring_to_components[ring_id]
        parent_c = -1 # Component closer to C0 (exterior)
        
        # Determine which component is the parent based on the BFS tree structure
        # ParentComp[x] stores the component from which x was visited in BFS from C0
        if c1 < len(ParentComp) and ParentComp[c1] == c2: parent_c = c2
        elif c2 < len(ParentComp) and ParentComp[c2] == c1: parent_c = c1
        # Handle cases involving C0 or dummy components (children of C0)
        # Need to ensure indices are valid before accessing ParentComp
        elif c1 == 0 and c2 < len(ParentComp) and ParentComp[c2] == 0: parent_c = 0
        elif c2 == 0 and c1 < len(ParentComp) and ParentComp[c1] == 0: parent_c = 0

        if parent_c == -1 : continue # Error or unexpected structure

        # Determine the parent ring ID based on the component hierarchy
        if parent_c == 0: # If the parent component is C0, this ring is a top-level ring
            ParentRingID = VIRTUAL_ROOT
        else:
            # Find the ring connecting parent_c to its parent (grandparent_c)
            grandparent_c = ParentComp[parent_c]
            # Look up the ring ID using the stored map CompEdgeRing
            ParentRingID = CompEdgeRing.get((grandparent_c, parent_c), -1)
            if ParentRingID == -1: continue # Error finding parent ring ID

        # Add edge (ParentRingID -> ring_id) to the ring hierarchy tree
        adjRing[ParentRingID].append(ring_id)

    # --- Step 4: Dynamic Programming on the Ring Hierarchy Tree ---
    dp_memo = {} # Memoization table for DP states: {ring_id: (dp0, dp1)}

    # Recursive DP function
    # Computes max strength for subtree rooted at ring `u`
    # Returns tuple: (max strength NOT using ring u, max strength USING ring u)
    def dfs_dp(u):
        # Check memoization table
        state = dp_memo.get(u)
        if state is not None: return state

        # Base case calculation / initialization for node u
        dp0 = 0 # Max strength if ring u is NOT used
        dp1 = 0 # Max strength if ring u IS used
        
        # If u is a real ring (not virtual root), its strength contributes if used (dp1)
        if u != VIRTUAL_ROOT:
            dp1 = ring_strengths[u]
        
        # Aggregate results from children subtrees
        for v in adjRing[u]: # Iterate over children rings v of ring u
            res_v0, res_v1 = dfs_dp(v) # Recursively get DP results for child v
            
            # If u is NOT used, we can choose the best option for child v (use or not use)
            dp0 += max(res_v0, res_v1)
            
            # If u IS used, we CANNOT use its immediate child v (due to problem constraint)
            dp1 += res_v0 

        # Store result in memoization table and return
        dp_memo[u] = (dp0, dp1)
        return dp0, dp1

    # Calculate the final answer by calling DP starting from the virtual root.
    # The virtual root represents the state outside all top-level rings.
    # Since it's not a real ring, we can't "use" it. The answer is its dp0 value.
    final_res0, _ = dfs_dp(VIRTUAL_ROOT)
    print(final_res0) 

solve()
0