結果
問題 |
No.2183 LCA on Rational Tree
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:19:23 |
言語 | PyPy3 (7.3.15) |
結果 |
TLE
|
実行時間 | - |
コード長 | 4,125 bytes |
コンパイル時間 | 437 ms |
コンパイル使用メモリ | 82,568 KB |
実行使用メモリ | 439,348 KB |
最終ジャッジ日時 | 2025-05-14 13:20:39 |
合計ジャッジ時間 | 6,896 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge4 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | TLE * 1 -- * 5 |
ソースコード
import math import sys # Function to compute the greatest common divisor (GCD) efficiently. # Using math.gcd is generally fast as it's likely implemented in C. def gcd(a, b): """Computes the greatest common divisor of a and b.""" return math.gcd(a, b) def solve(): """Solves a single query for LCA.""" # Read the input fractions p(u)/q(u) and p(v)/q(v) P = list(map(int, sys.stdin.readline().split())) pu1, qu1, pv1, qv1 = P[0], P[1], P[2], P[3] # Dictionary to store the nodes encountered along the path starting from u1. # Key: tuple (p, q) representing the rational number p/q. # Value: The number of steps taken from u1 to reach this node. Useful for debugging or potential optimizations, but not strictly needed for finding LCA here. u_path = {} # Start tracing the path from u1 = pu1/qu1 curr_p = pu1 curr_q = qu1 # Set a maximum number of steps to prevent excessively long computations or potential infinite loops. # This value is chosen based on typical competitive programming constraints and problem analysis. # If path length exceeds this, the solution might Time Limit Exceed or fail on edge cases. # Based on problem constraints and typical behavior of such structures, 2*10^6 seems reasonable. MAX_STEPS = 2 * 10**6 # Generate the path starting from u1 count = 0 while count < MAX_STEPS: # Store the current node (p, q) and its step count (distance from u1) u_path[(curr_p, curr_q)] = count # Calculate the next node p'/q' by applying the operation: (p+1)/(q+1) simplified. next_p_num = curr_p + 1 next_q_num = curr_q + 1 # Find the greatest common divisor of numerator and denominator to simplify the fraction. common_divisor = gcd(next_p_num, next_q_num) # Compute the simplified numerator and denominator for the next node. # Integer division // is used. next_p = next_p_num // common_divisor next_q = next_q_num // common_divisor # Optional check: if the state (p, q) doesn't change, break to avoid potential infinite loop. # This condition shouldn't be met for valid inputs in the vertex set V defined as 1 <= p < q. if next_p == curr_p and next_q == curr_q: break # Move to the next node curr_p = next_p curr_q = next_q count += 1 # Now, trace the path starting from v1 = pv1/qv1 curr_p = pv1 curr_q = qv1 count = 0 while count < MAX_STEPS: # Check if the current node (p, q) from v1's path exists in the path generated from u1. # The `in` check on dictionary keys is O(1) on average. if (curr_p, curr_q) in u_path: # If found, this is the first common node encountered, which is the Lowest Common Ancestor (LCA). # Print its numerator and denominator. print(f"{curr_p} {curr_q}") # Return after finding the LCA for this query. return # Calculate the next node in the path from v1 next_p_num = curr_p + 1 next_q_num = curr_q + 1 common_divisor = gcd(next_p_num, next_q_num) next_p = next_p_num // common_divisor next_q = next_q_num // common_divisor # Optional check: state doesn't change if next_p == curr_p and next_q == curr_q: break # Move to the next node curr_p = next_p curr_q = next_q count += 1 # If this point is reached, it means the LCA was not found within MAX_STEPS. # This could happen if MAX_STEPS is too small for some test cases, or if there's an issue # with the understanding of the problem structure (e.g., paths diverge indefinitely or cycle differently). # For the contest setting, it's usually assumed that a solution exists within reasonable bounds. # Read the number of queries from standard input Q = int(sys.stdin.readline()) # Process each query one by one for _ in range(Q): solve()