D - 花火の消去 / Firework Elimination 解説 by admin
Claude 4.6 Opus (Thinking)Overview
When each firework \(i\) is launched, it destroys target \(T_i\). This structure forms a “directed graph where each node has out-degree exactly 1 (functional graph).” The problem of maximizing the number of launched fireworks reduces to counting the number of cycles in this graph, and the answer is \(N - (\text{number of cycles})\).
Analysis
Understanding the Graph Structure
By drawing an edge from each firework \(i\) to firework \(T_i\), we obtain a directed graph where every node has out-degree exactly 1 (functional graph). This graph consists of several cycles and trees flowing into those cycles (ρ-shaped structures).
Nodes Not Belonging to Cycles (Tree Parts)
For a node \(i\) that does not belong to a cycle, if \(i\) is launched first, it destroys \(T_i\), but if \(T_i\) is launched first, \(i\) is not destroyed. Therefore, by launching in the appropriate order (from leaves toward the root of the tree), all nodes in the tree parts can be launched without being destroyed.
Loss from Cycle Parts
The problem lies in the cycles. Consider a cycle \(v_1 \to v_2 \to \cdots \to v_k \to v_1\). Launching \(v_1\) destroys \(v_2\), launching \(v_2\) destroys \(v_3\), and so on.
No matter which node in the cycle is launched first, the shockwave from the first launched firework destroys exactly one next firework. The remaining nodes can be launched in order by skipping the destroyed one, but since the destroyed node’s shockwave does not activate, no further chain of destruction occurs.
In other words, the best we can do is that exactly one node is destroyed per cycle.
Conclusion
No nodes are lost in the tree parts, and exactly one is lost per cycle, so:
\[\text{answer} = N - (\text{number of cycles})\]
Concrete Example
For \(N = 4\), \(T = [2, 1, 4, 3]\), the edges are \(1 \to 2, 2 \to 1, 3 \to 4, 4 \to 3\), giving 2 cycles (\(\{1,2\}\) and \(\{3,4\}\)), so the answer is \(4 - 2 = 2\).
Algorithm
- Build a functional graph by drawing an edge from each node \(i\) to \(T_i\).
- Traverse the graph using DFS (depth-first search) and count the number of cycles.
- Follow a path from an unvisited node; if a node currently “being explored” is reached again, one cycle is detected.
- If a node already “fully explored” is reached, it is not a new cycle.
- Output \(N - (\text{number of cycles})\) as the answer.
Complexity
- Time complexity: \(O(N)\) (each node is visited at most a constant number of times)
- Space complexity: \(O(N)\) (for the graph, visit states, and path recording)
Implementation Notes
Cycle detection is straightforward in a functional graph. By simply following each node to its next node and maintaining a
visitedarray with three states — “unvisited (0),” “being explored (1),” and “fully explored (2)” — a cycle is identified when we return to a node that is currently being explored.Since \(N\) can be as large as \(10^6\), recursive DFS risks stack overflow. In the code, this is avoided by iteratively following paths using a
whileloop.In Python, it is important to read input efficiently using
sys.stdin.buffer.read().Source Code
import sys
from collections import deque
def solve():
input_data = sys.stdin.buffer.read().split()
N = int(input_data[0])
T = [int(input_data[i+1]) - 1 for i in range(N)]
# Count cycles in functional graph
# Each node has out-degree 1
visited = [0] * N # 0: unvisited, 1: in progress, 2: done
num_cycles = 0
for start in range(N):
if visited[start] != 0:
continue
path = []
node = start
while visited[node] == 0:
visited[node] = 1
path.append(node)
node = T[node]
if visited[node] == 1:
# Found a cycle - count it
# Find where the cycle starts in path
cycle_start = node
idx = 0
while path[idx] != cycle_start:
idx += 1
num_cycles += 1
for p in path:
visited[p] = 2
print(N - num_cycles)
solve()
This editorial was generated by claude4.6opus-thinking.
投稿日時:
最終更新: