結果
問題 |
No.1931 Fraction 2
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:09:31 |
言語 | PyPy3 (7.3.15) |
結果 |
TLE
|
実行時間 | - |
コード長 | 9,986 bytes |
コンパイル時間 | 392 ms |
コンパイル使用メモリ | 82,100 KB |
実行使用メモリ | 104,616 KB |
最終ジャッジ日時 | 2025-05-14 13:10:51 |
合計ジャッジ時間 | 9,614 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 10 TLE * 1 -- * 25 |
ソースコード
import sys import math # Set higher recursion depth for extended_gcd if needed, though iterative is safer # sys.setrecursionlimit(2000) # Function to compute greatest common divisor def gcd(a, b): """Computes the greatest common divisor of a and b.""" while b: a, b = b, a % b return a # Function for Extended Euclidean Algorithm def extended_gcd(a, b): """ Computes extended Euclidean Algorithm. Returns tuple (d, x, y) such that d = gcd(a, b) and ax + by = d. """ 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 # Function to compute modular inverse def modInverse(a, m): """ Computes the modular multiplicative inverse of a modulo m. Raises ValueError if inverse does not exist (i.e., gcd(a, m) != 1). """ d, x, y = extended_gcd(a, m) if d != 1: raise ValueError(f"Modular inverse does not exist for a={a}, m={m}, gcd={d}") # Return x mod m, ensuring result is positive return (x % m + m) % m # Function for modular exponentiation def fast_pow(base, power, modulus): """ Computes (base^power) % modulus using binary exponentiation. """ result = 1 base %= modulus # Ensure base is within modulo range while power > 0: if power % 2 == 1: result = (result * base) % modulus base = (base * base) % modulus power //= 2 return result # --- Sieve and Factorization --- MAX_VAL = 200001 # Maximum value for A_i, B_i + 1 spf = [i for i in range(MAX_VAL)] # Smallest Prime Factor array primes = [] # List of primes up to MAX_VAL def sieve(): """ Sieve of Eratosthenes to precompute Smallest Prime Factor (SPF) for numbers up to MAX_VAL. """ is_prime = [True] * MAX_VAL is_prime[0] = is_prime[1] = False for i in range(2, MAX_VAL): if is_prime[i]: spf[i] = i primes.append(i) # Mark multiples of i as not prime and set their SPF # Start from i*i to optimize for multiple in range(i * i, MAX_VAL, i): if is_prime[multiple]: # Check if SPF hasn't been set yet is_prime[multiple] = False spf[multiple] = i sieve() # Precompute SPF table def get_prime_factorization(num): """ Factorizes a number using the precomputed SPF table. Returns a dictionary {prime: exponent}. """ factors = {} if num <= 0: return {} # Handle non-positive inputs if num == 1: return {} # Base case for 1 while num > 1: p = spf[num] count = 0 while num > 0 and num % p == 0: # Check divisibility and ensure num remains positive num //= p count += 1 if count > 0: # Store the prime factor and its exponent factors[p] = count # Optimization: if the remaining number is prime (its SPF is itself) if num > 1 and spf[num] == num: factors[num] = factors.get(num, 0) + 1 break # Factorization complete # Exit loop if num becomes 1 if num == 1: break return factors # --- Main Solve Function --- MOD = 998244353 # The modulus specified in the problem def solve(): """ Main logic to solve the fraction sum problem. """ N = int(sys.stdin.readline()) A = [] # List of numerators B = [] # List of denominators B_factors = [] # List of prime factorizations of denominators for i in range(N): line = sys.stdin.readline().split() ai = int(line[0]) bi = int(line[1]) # Basic validation based on problem constraints if not (1 <= ai <= 200000): raise ValueError(f"A_i={ai} out of bounds 1..200000") if not (1 <= bi <= 200000): raise ValueError(f"B_i={bi} out of bounds 1..200000") A.append(ai) B.append(bi) if bi >= MAX_VAL: raise ValueError(f"B_i={bi} exceeds MAX_VAL limit {MAX_VAL-1}") B_factors.append(get_prime_factorization(bi)) # Compute maximum exponent E_p for each prime p involved in any B_i max_exponents = {} # {prime: max_exponent} involved_primes = set() # Set of primes that divide at least one B_i for factors in B_factors: for p, exp in factors.items(): involved_primes.add(p) # Update the maximum exponent seen so far for prime p if p not in max_exponents or exp > max_exponents[p]: max_exponents[p] = exp involved_primes_list = sorted(list(involved_primes)) # Sorted list of primes K = len(involved_primes_list) # Number of distinct prime factors across all B_i # Calculate L mod MOD, where L = lcm(B_1, ..., B_N) L_mod = 1 for p in involved_primes_list: Ep = max_exponents.get(p, 0) if Ep > 0: # Only include primes with positive maximum exponent term = fast_pow(p, Ep, MOD) L_mod = (L_mod * term) % MOD # Calculate C mod MOD, where C is the numerator of the sum before reduction # C = sum(A_i * (L / B_i)) # We compute (L/B_i) mod MOD as (L mod MOD) * (B_i^{-1} mod MOD) mod MOD C_mod = 0 for i in range(N): if B[i] == 0: continue # Should not happen based on constraints # B_i^{-1} mod MOD exists because B_i <= 200000 < MOD and MOD is prime Bi_inv_mod = fast_pow(B[i], MOD - 2, MOD) # Using Fermat's Little Theorem for prime MOD term = (A[i] * L_mod) % MOD term = (term * Bi_inv_mod) % MOD C_mod = (C_mod + term) % MOD # Compute G = gcd(C, L). We need its prime factorization G = product(p^gp) G_mod = 1 # G mod MOD G_factors = {} # Stores {prime: exponent gp} for G # For each prime p involved, compute gp = min(Ep, nu_p(C)) # where nu_p(C) is the exponent of p in the prime factorization of C. for p_idx, p in enumerate(involved_primes_list): Ep = max_exponents[p] # Maximum exponent of p in any B_i # Compute C mod p^(Ep+1) to determine nu_p(C) up to Ep Mp_val = pow(p, Ep + 1) # Exact value of p^(Ep+1) # Compute L'_p = L / p^Ep = product_{q!=p} q^Eq modulo Mp_val L_prime_p_mod_Mp = 1 for q_idx, q in enumerate(involved_primes_list): if q != p: Eq = max_exponents.get(q, 0) if Eq > 0: term = fast_pow(q, Eq, Mp_val) L_prime_p_mod_Mp = (L_prime_p_mod_Mp * term) % Mp_val # Calculate C mod Mp_val C_mod_Mp = 0 for i in range(N): Bi_p_part_exp = B_factors[i].get(p, 0) # Exponent of p in B_i # Calculate B'_ip = B[i] / p^e_ip. This is the part of B_i coprime to p. p_pow_Bi_p_part_exp = pow(p, Bi_p_part_exp) if B[i] == 0: continue if p_pow_Bi_p_part_exp == 0: raise ValueError("p^exp resulted in 0") # Impossible for p>=2 B_prime_ip_val = B[i] // p_pow_Bi_p_part_exp if B_prime_ip_val == 0: continue # Should only happen if B[i]=0 initially # Calculate (L/B_i) mod Mp_val = (p^(Ep - e_ip) * Z_ip) mod Mp_val # where Z_ip = L'_p / B'_ip B_prime_ip_mod_Mp = B_prime_ip_val % Mp_val if B_prime_ip_mod_Mp == 0: # This implies gcd(B'_ip, Mp) = Mp != 1. But gcd(B'_ip, p)=1, so gcd(B'_ip, Mp)=1. # This case should be impossible. Included for robustness / debugging. raise ValueError(f"Impossible case: B_prime_ip_mod_Mp == 0 for i={i}, p={p}") # B'_ip is coprime to Mp=p^(Ep+1), so inverse exists B_prime_ip_inv_mod_Mp = modInverse(B_prime_ip_mod_Mp, Mp_val) # Z_ip mod Mp = (L'_p mod Mp) * (B'_ip^{-1} mod Mp) mod Mp Z_ip_mod_Mp = (L_prime_p_mod_Mp * B_prime_ip_inv_mod_Mp) % Mp_val # Calculate p^(Ep - e_ip) mod Mp p_power_term = fast_pow(p, Ep - Bi_p_part_exp, Mp_val) # Calculate A_i * (L/B_i) mod Mp Ai_mod_Mp = A[i] % Mp_val # Ensure A[i] is taken mod Mp term_i = (Ai_mod_Mp * p_power_term) % Mp_val term_i = (term_i * Z_ip_mod_Mp) % Mp_val C_mod_Mp = (C_mod_Mp + term_i) % Mp_val # Determine nu_p(C) based on C_mod_Mp if C_mod_Mp == 0: # If C = 0 mod p^(Ep+1), then nu_p(C) >= Ep+1 nu_p_C = Ep + 1 else: # Calculate the exact exponent of p dividing C_mod_Mp temp_C = C_mod_Mp nu_p_C = 0 # Keep dividing by p until it's no longer divisible while temp_C > 0 and temp_C % p == 0: temp_C //= p nu_p_C += 1 # gp = min(exponent of p in L, exponent of p in C) gp = min(Ep, nu_p_C) G_factors[p] = gp # Store the exponent of p in G # Accumulate G mod MOD if gp > 0: G_mod = (G_mod * fast_pow(p, gp, MOD)) % MOD # Final computation of c and d modulo MOD # c = (C / G) mod MOD = (C mod MOD) * (G^{-1} mod MOD) mod MOD # d = (L / G) mod MOD = product(p^(Ep - gp)) mod MOD if G_mod == 0: # G mod MOD = 0 impossible since MOD is prime > max(p) pass # G^{-1} mod MOD exists since G is not a multiple of MOD G_inv_mod = fast_pow(G_mod, MOD - 2, MOD) final_c = (C_mod * G_inv_mod) % MOD # Calculate d = L/G mod MOD final_d = 1 for p in involved_primes_list: Ep = max_exponents.get(p, 0) gp = G_factors.get(p, 0) exp_diff = Ep - gp # Exponent of p in d if exp_diff > 0: term = fast_pow(p, exp_diff, MOD) final_d = (final_d * term) % MOD # Output the result print(final_c, final_d) # --- Execution --- solve()