結果
問題 |
No.195 フィボナッチ数列の理解(2)
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:24:01 |
言語 | PyPy3 (7.3.15) |
結果 |
AC
|
実行時間 | 79 ms / 5,000 ms |
コード長 | 9,094 bytes |
コンパイル時間 | 197 ms |
コンパイル使用メモリ | 82,348 KB |
実行使用メモリ | 76,988 KB |
最終ジャッジ日時 | 2025-05-14 13:25:23 |
合計ジャッジ時間 | 2,852 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 22 |
ソースコード
import math # Extended Euclidean Algorithm: ax + by = gcd(a,b) # Returns (g, x, y) where g = gcd(a,b) and ax + by = g def extended_gcd(a, b): if a == 0: return b, 0, 1 d, x1, y1 = extended_gcd(b % a, a) x = y1 - (b // a) * x1 y = x1 return d, x, y def solve(): X, Y, Z = map(int, input().split()) distinct_target_values = sorted(list(set([X, Y, Z]))) # Max k for F_AB(k). F_std(46) ~ 1.8e9, F_std(47) ~ 2.9e9. # So k up to about 47 should be enough. N_MAX_K_INDEX = 47 # Precompute standard Fibonacci numbers: F_std[0]=0, F_std[1]=1, ... # Need up to F_std[N_MAX_K_INDEX-1] for coefficients. # fib_std array will have size N_MAX_K_INDEX, storing F_std[0]...F_std[N_MAX_K_INDEX-1] # Or size N_MAX_K_INDEX+1 to store up to F_std[N_MAX_K_INDEX] if k can be N_MAX_K_INDEX+1 # Coefficients are F_std(k-2), F_std(k-1). If max k is N_MAX_K_INDEX, max index needed is N_MAX_K_INDEX-1. fib_std = [0] * (N_MAX_K_INDEX + 1) # Store F_std[0] to F_std[N_MAX_K_INDEX] if N_MAX_K_INDEX >=0: fib_std[0] = 0 if N_MAX_K_INDEX >=1: fib_std[1] = 1 for i in range(2, N_MAX_K_INDEX + 1): fib_std[i] = fib_std[i-1] + fib_std[i-2] # Get coefficients (cA, cB) for F_AB(k) = cA*A + cB*B def get_coeffs(k_idx): if k_idx == 1: return 1, 0 if k_idx == 2: return 0, 1 # For k >= 3, F_AB(k) = F_std(k-2)*A + F_std(k-1)*B # Check if indices k-2, k-1 are valid for precomputed fib_std if k_idx < 3 or k_idx - 1 > N_MAX_K_INDEX : return float('inf'), float('inf') # Invalid k or out of bounds for fib_std return fib_std[k_idx-2], fib_std[k_idx-1] min_A_sol, min_B_sol = -1, -1 candidate_AB_pairs = [] # Part 1: Two points define A, B for k1 in range(1, N_MAX_K_INDEX + 1): for k2 in range(1, N_MAX_K_INDEX + 1): if k1 == k2: continue cA1, cB1 = get_coeffs(k1) cA2, cB2 = get_coeffs(k2) if cA1 == float('inf') or cA2 == float('inf'): continue for val1 in distinct_target_values: for val2 in distinct_target_values: D = cA1 * cB2 - cA2 * cB1 if D == 0: continue A_num = val1 * cB2 - val2 * cB1 B_num = cA1 * val2 - cA2 * val1 if A_num % D == 0 and B_num % D == 0: A = A_num // D B = B_num // D if A > 0 and B > 0: candidate_AB_pairs.append((A, B)) # Part 2: One point defines A, B (Diophantine equation) for k_idx in range(1, N_MAX_K_INDEX + 1): for val_target in distinct_target_values: cA, cB = get_coeffs(k_idx) if cA == float('inf'): continue # k_idx invalid or too large if k_idx == 1: # A = val_target A, B = val_target, 1 if A > 0: candidate_AB_pairs.append((A,B)) elif k_idx == 2: # B = val_target A, B = 1, val_target if B > 0: candidate_AB_pairs.append((A,B)) else: # cA*A + cB*B = val_target. cA, cB >= 1 for k>=3. g, x0, y0 = extended_gcd(cA, cB) if val_target % g != 0: continue A_p = x0 * (val_target // g) B_p = y0 * (val_target // g) term_B_for_A_update = cB // g # Coefficient for t in A_s = A_p + t * term_B_for_A_update term_A_for_B_update = cA // g # Coefficient for t in B_s = B_p - t * term_A_for_B_update # We need A_s = A_p + t*term_B_for_A_update >= 1 # We need B_s = B_p - t*term_A_for_B_update >= 1 # term_B_for_A_update = F_std(k-1)/g > 0 for k>=3 # term_A_for_B_update = F_std(k-2)/g > 0 for k>=3 (F_std(1)=1) # t >= (1 - A_p) / term_B_for_A_update t_min_for_A_cond = math.ceil((1 - A_p) / term_B_for_A_update) # t <= (B_p - 1) / term_A_for_B_update t_max_for_B_cond = math.floor((B_p - 1) / term_A_for_B_update) if t_min_for_A_cond <= t_max_for_B_cond: # Valid range for t exists. To minimize A, pick t = t_min_for_A_cond. t = t_min_for_A_cond A = A_p + t * term_B_for_A_update B = B_p - t * term_A_for_B_update if A > 0 and B > 0: candidate_AB_pairs.append((A, B)) if not candidate_AB_pairs and (min_A_sol == -1) : # Check if list is empty and no solution yet print("-1") return candidate_AB_pairs = sorted(list(set(candidate_AB_pairs))) max_val_XYZ = max(X,Y,Z) for A_cand, B_cand in candidate_AB_pairs: generated_terms = set() _f1, _f2 = A_cand, B_cand # Generate terms and add to set # Stop if terms grow too large or after N_MAX_K_INDEX iterations for i in range(N_MAX_K_INDEX + 2): # Iterate a bit more than max_k if i == 0: current_term = _f1 elif i == 1: current_term = _f2 else: _f_next = _f1 + _f2 _f1 = _f2 _f2 = _f_next current_term = _f1 # This is F(i-1+1) = F(i) if loop index is i # After update, _f1 holds F(i+1) using 0-indexed loop # Correct: term added should be the first term of the pair. # Iter 0: add A. Iter 1: add B. Iter 2: add A+B. # To match F_AB(i+1) structure if loop index `i` is 0-based count of steps # i=0: current_term = A_cand = F_AB(1) # i=1: current_term = B_cand = F_AB(2) # i=2: _f_next = A_cand+B_cand. _f1 becomes B_cand, _f2 becomes A_cand+B_cand. Current_term = _f1 (B_cand). This is wrong. # Let's fix sequence generation: if i == 0: term_to_add = A_cand elif i == 1: term_to_add = B_cand else: # i >= 2 # At this point, _f1 = F_AB(i), _f2 = F_AB(i+1) # We want to add F_AB(i+1) # Previous state: _f1 was F_AB(i-1), _f2 was F_AB(i) # New term is _f1 + _f2 (old values) = F_AB(i+1) # if i=2, new term is A+B = F_AB(3) if i==2: _f1, _f2 = A_cand, B_cand # Reset _f1, _f2 for calculating F(3) onwards next_val = _f1 + _f2 _f1 = _f2 _f2 = next_val term_to_add = _f1 # This is F_AB(i) as _f1 stores the (i-1)th term for next F(i) calc # e.g., after first A+B, _f1=B, _f2=A+B. F_AB(3) = A+B added using _f1 of next step. # This means for loop i, we add F_AB(i+1) # More simply: # f_list = [A_cand, B_cand] # generated_terms.add(A_cand) # generated_terms.add(B_cand) # loop: f_new = f_list[-1]+f_list[-2]; f_list.append(f_new); generated_terms.add(f_new) if term_to_add > max_val_XYZ + abs(B_cand) + abs(A_cand) and term_to_add not in [X,Y,Z]: # Heuristic margin # If A_cand, B_cand are large, max_val_XYZ could be small. Sums can exceed quickly. # A better bound for breaking is if term_to_add > max_val_XYZ and all X,Y,Z < term_to_add pass # The loop limit N_MAX_K_INDEX + 2 is the primary stop generated_terms.add(term_to_add) if term_to_add > 2 * 10**9 : break # Hard stop for very large terms / overflow # After generating sequence (or part of it): # Check if X, Y, Z are all in generated_terms # Reset for actual generation: generated_terms_check = set() curr1, curr2 = A_cand, B_cand for _ in range(N_MAX_K_INDEX + 2): # Max relevant terms if curr1 > max_val_XYZ * 2 + max(A_cand,B_cand) and curr1 not in [X,Y,Z]: # Heuristic bound for adding break # Optimization if terms grow way too large generated_terms_check.add(curr1) if curr1 > 2.1 * 10**9: break # Safety break curr_next = curr1 + curr2 curr1 = curr2 curr2 = curr_next found_X = X in generated_terms_check found_Y = Y in generated_terms_check found_Z = Z in generated_terms_check if found_X and found_Y and found_Z: if min_A_sol == -1 or A_cand < min_A_sol or \ (A_cand == min_A_sol and B_cand < min_B_sol): min_A_sol = A_cand min_B_sol = B_cand if min_A_sol != -1: print(min_A_sol, min_B_sol) else: print("-1") solve()