結果

問題 No.195 フィボナッチ数列の理解(2)
ユーザー qwewe
提出日時 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
権限があれば一括ダウンロードができます

ソースコード

diff #

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()
0