公式

E - 展望台への登山 / Climbing to the Observation Deck 解説 by admin

gemini-3.5-flash-high

Overview

This problem asks us to find the minimum cost path from the start to the goal under the constraints that we must visit at least a minimum number of checkpoints and the number of visits to each terrain type must be even.

By focusing on the small constraint \(M \le 8\), we can solve this problem efficiently by combining Bit DP and standard Dynamic Programming (DP).

Analysis

1. State Representation

In this problem, during the transition, we need to keep track of: where we currently are (which checkpoint), how many checkpoints we have visited so far, and how many times we have visited each terrain type (odd or even number of times).

  • Current Location: Let \(i\) be the last checkpoint visited.
  • Number of Visited Checkpoints: The number of visits \(s\) must be at least \(K\). Once we have visited \(K\) or more checkpoints, we do not need to count the exact number anymore and can group them into a single state “visited \(K\) or more checkpoints”. Therefore, the number of visited checkpoints can be managed in \(K+1\) states from \(0\) to \(K\).
  • Parity of Terrain Type Visits: The number of visits to each terrain type must be even. Since \(M \le 8\) is extremely small, we can represent the parity of the visit count for each terrain type (odd = 1, even = 0) as an \(M\)-bit integer (mask). The number of states is \(2^M \le 256\).

2. Naive Approach and Improvement

If we search all combinations of checkpoint visits, there are \(2^N\) ways just to choose the checkpoints, which is far too slow for \(N \le 150\). However, if we define a DP using the three pieces of information above (current location, number of visited checkpoints, and parity mask) as the state, we only need to keep the minimum cost among the paths reaching the same state. This drastically reduces the search space.

Algorithm

DP Table Definition

We define the DP table as follows:

\[dp[i][j][mask] := \text{the minimum cost when the last visited checkpoint is } i\text{, the number of visited checkpoints is } j\text{ (capped at } K\text{), and the visit parity state is } mask\]

  • \(0 \le i \le N\)
  • \(0 \le j \le K\)
  • \(0 \le mask < 2^M\)

Initial State

We start from the starting point \(0\) (where no checkpoints have been visited yet). - \(dp[0][0][0] = 0\) - All other elements are initialized to \(\infty\) (unreachable).

Transitions

From the current location \(i\), we iterate over all possible next checkpoints \(next\_i\) (\(i < next\_i \le N\)).

For the current state \(dp[i][j][mask]\), the transition targets are as follows: - Next number of visited checkpoints: \(next\_j = \min(j + 1, K)\) - Next parity state: \(next\_mask = mask \oplus (1 \ll t_{next\_i})\) (where \(\oplus\) represents the bitwise XOR operation) - Transition formula: $\(dp[next\_i][next\_j][next\_mask] = \min(dp[next\_i][next\_j][next\_mask], dp[i][j][mask] + C_{i, next\_i})\)$

Calculating the Answer

After completing all DP transitions, we find the minimum cost by adding the movement cost to the goal \(N+1\). A valid final state requires the number of visited checkpoints to be \(K\) (representing \(K\) or more) and the parity state to be \(0\) (representing an even number of visits for all terrain types).

  1. When visiting at least one checkpoint: We add the cost of moving directly from each checkpoint \(i\) (\(1 \le i \le N\)) to the goal \(N+1\): $\(\min_{1 \le i \le N} (dp[i][K][0] + C_{i, N+1})\)$

  2. When visiting no checkpoints (only possible when \(K = 0\)): The cost of moving directly from the start to the goal, \(C_{0, N+1}\), is also a candidate.

The minimum of these values will be the answer. If no valid path can be formed (the minimum value remains \(\infty\)), output -1.

Complexity

Time Complexity

  • Number of States: \(N \times (K + 1) \times 2^M\)
  • Number of Transitions: From each state, there are at most \(N\) choices for the next checkpoint \(next\_i\).

Therefore, the total time complexity is: $\(O(N^2 \cdot K \cdot 2^M)\)$

Even in the worst-case scenario (\(K = N \approx 150\), \(M = 8\)), the number of loop iterations is approximately \(150^3 \times 2^8 \approx 8.6 \times 10^8\). In the implementation, by pruning unnecessary transitions (skipping transitions from states with a value of \(\infty\)), we can significantly reduce the execution time, easily fitting within the time limit.

Space Complexity

The size of the DP table is \((N+1) \times (K+1) \times 2^M\). $\(O(N \cdot K \cdot 2^M)\)\( This results in a 3D array with \)150 \times 150 \times 256 \approx 5.7 \times 10^6$ elements, which is well within the memory limit.

Implementation Points

  • Optimization via Bitwise Operations: Updating the parity of terrain types can be done extremely quickly using the XOR operation (^).

  • Pruning (Skipping Useless Transitions): Avoid transitioning from states where dp[i][j] remains at its initial value of \(\infty\). In the code, by pre-collecting active_states and only iterating over reachable states, the solution runs fast even in Python.

  • Index Adjustments: Since the terrain types \(t_i\) are given as \(1\)-based, converting them to \(0\)-based (t[i] - 1) makes them easier to handle with bit shifts and simplifies the implementation.

    Source Code

import sys


def solve():
    input = sys.stdin.read
    data = input().split()
    if not data:
        return

    N = int(data[0])
    M = int(data[1])
    K = int(data[2])

    t = [0] + [int(x) - 1 for x in data[3 : 3 + N]]

    idx = 3 + N
    C = [[0] * (N + 2) for _ in range(N + 1)]
    for i in range(N + 1):
        num_elements = N + 1 - i
        row = [int(x) for x in data[idx : idx + num_elements]]
        idx += num_elements
        for offset, val in enumerate(row):
            C[i][i + 1 + offset] = val

    INF = 10**18

    num_masks = 1 << M
    dp = [[[INF] * num_masks for _ in range(K + 1)] for _ in range(N + 1)]
    dp[0][0][0] = 0

    type_bits = [1 << x for x in t]

    for i in range(N):
        C_i = C[i]
        dp_i = dp[i]
        for j in range(min(i, K) + 1):
            dp_i_j = dp_i[j]
            active_states = [
                (mask, val) for mask, val in enumerate(dp_i_j) if val < INF
            ]
            if not active_states:
                continue

            next_j = min(j + 1, K)
            for next_i in range(i + 1, N + 1):
                cost = C_i[next_i]
                type_bit = type_bits[next_i]
                dp_next = dp[next_i][next_j]
                for mask, dp_val in active_states:
                    val = dp_val + cost
                    n_mask = mask ^ type_bit
                    if val < dp_next[n_mask]:
                        dp_next[n_mask] = val

    ans = INF
    if K == 0:
        ans = min(ans, C[0][N + 1])

    for i in range(1, N + 1):
        cost_to_dest = C[i][N + 1]
        val = dp[i][K][0]
        if val < INF:
            ans = min(ans, val + cost_to_dest)

    if ans >= INF:
        print(-1)
    else:
        print(ans)


if __name__ == "__main__":
    solve()

This editorial was generated by gemini-3.5-flash-high.

投稿日時:
最終更新: