結果
問題 |
No.2062 Sum of Subset mod 999630629
|
ユーザー |
![]() |
提出日時 | 2025-05-14 12:56:18 |
言語 | PyPy3 (7.3.15) |
結果 |
TLE
|
実行時間 | - |
コード長 | 10,406 bytes |
コンパイル時間 | 217 ms |
コンパイル使用メモリ | 82,724 KB |
実行使用メモリ | 127,024 KB |
最終ジャッジ日時 | 2025-05-14 12:58:34 |
合計ジャッジ時間 | 29,542 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge4 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 22 TLE * 1 -- * 6 |
ソースコード
# -*- coding: utf-8 -*- import sys import collections # Use optimized input reading for speed in competitive programming input = sys.stdin.readline def solve(): N = int(input()) # Read the integer sequence A # A = list(map(int, input().split())) # Standard input read # Slightly optimized input reading for large N A = [] raw_A = input().split() for x_str in raw_A: A.append(int(x_str)) # Define the two primes given in the problem P1 = 999630629 # Modulo for f(S) P2 = 998244353 # Modulo for the final answer # The final answer should be modulo P2 MOD = P2 # Calculate SumA = sum(A_i). Python integers handle arbitrary size. sum_A = 0 for x in A: sum_A += x # Calculate 2^(N-1) mod P2 using modular exponentiation # Constraints state N >= 1 pow2_N_minus_1 = pow(2, N - 1, MOD) # Calculate the first term T = (2^(N-1) * SumA) mod P2 # We need SumA mod P2 for this calculation term1 = (pow2_N_minus_1 * (sum_A % MOD)) % MOD # The problem formula derived is R = (T - P1 * Count) mod P2 # where Count is the number of non-empty subsets S such that sum(A_i for i in S) >= P1. # We showed that Count = sum_{k=0..K} c_k mod P2, where K = SumA - P1 and c_k is the number of subsets summing to k. count = 0 # Initialize count, default is 0 if SumA < P1 # Only need to compute Count if SumA >= P1 if sum_A >= P1: # Calculate K = SumA - P1. This is the maximum degree we need for the polynomial coefficients. K = sum_A - P1 # Count frequencies of each distinct value in A counts = {} for x in A: # Check A_i >= 1 per constraints. If 0 were allowed, they wouldn't affect sum but increase subset count. if x > 0: counts[x] = counts.get(x, 0) + 1 # If there are no positive values in A (e.g. A=[0,0]), SumA=0. This block wouldn't be reached if P1>=1. # If counts is empty, then there are no elements to form subsets. # Precompute factorials and inverse factorials modulo P2 for calculating combinations (nCr) MAX_N_FOR_FACT = N # Maximum 'n' for nCr is N fact = [1] * (MAX_N_FOR_FACT + 1) invfact = [1] * (MAX_N_FOR_FACT + 1) for i in range(1, MAX_N_FOR_FACT + 1): fact[i] = (fact[i-1] * i) % MOD # Calculate modular inverse using Fermat's Little Theorem (since P2 is prime) invfact[MAX_N_FOR_FACT] = pow(fact[MAX_N_FOR_FACT], MOD - 2, MOD) # Compute remaining inverse factorials iteratively using invfact[i] = invfact[i+1] * (i+1) for i in range(MAX_N_FOR_FACT - 1, -1, -1): invfact[i] = (invfact[i+1] * (i+1)) % MOD # Function to compute nCr mod P2 using precomputed factorials def nCr_mod(n, r): if r < 0 or r > n: return 0 # Safety check, should not happen with correct N if n > MAX_N_FOR_FACT: raise ValueError("n is too large for precomputed factorials") # nCr = n! / (r! * (n-r)!) num = fact[n] den = (invfact[r] * invfact[n-r]) % MOD return (num * den) % MOD # Prepare the base polynomials Q_v(x) = (1+x^v)^m_v for each distinct value v with frequency m_v. # We only need coefficients up to degree K. polys = [] for v in sorted(counts.keys()): # Iterate through distinct values sorted m_v = counts[v] # Maximum possible degree from this term is v * m_v. Cap at K. current_max_deg = min(K, v * m_v) # Initialize polynomial as list of coefficients [c0, c1, ..., c_max_deg] q_v = [0] * (current_max_deg + 1) has_higher_terms = False # Track if polynomial has terms other than constant 1 # Calculate coefficients using binomial theorem: (1+x^v)^m_v = sum_{j=0..m_v} C(m_v, j) * (x^v)^j for j in range(m_v + 1): term_deg = v * j if term_deg > K: # If degree exceeds K, stop for this polynomial break comb = nCr_mod(m_v, j) # Calculate C(m_v, j) mod P2 if comb > 0: # Only store non-zero terms q_v[term_deg] = comb if term_deg > 0: # Check if we added a term x^k with k > 0 has_higher_terms = True # Add the generated polynomial to the list if it's not just [0] # It will always have at least q_v[0]=1 unless m_v=0 which is not possible here. # Optimization: if q_v is just [1], meaning (1+x^v)^m_v contribution doesn't affect degrees up to K beyond constant term, # multiplying by 1 doesn't change anything. But handle it in multiplication logic instead. polys.append(q_v) # If there are no polynomials (e.g., N=0 or all A_i were 0), the product is 1. if not polys: final_poly = [1] else: # Use Number Theoretic Transform (NTT) for efficient polynomial multiplication. # Standard NTT parameters for MOD = 998244353: primitive root G = 3. G = 3 # NTT implementation def ntt(a, inv): n = len(a) # Length must be power of 2 # Bit reversal permutation j = 0 for i in range(1, n): rev = n >> 1 while j >= rev: j -= rev rev >>= 1 j += rev if i < j: a[i], a[j] = a[j], a[i] # Butterfly operations k = 1 while k < n: # Precompute roots of unity w_k_base = G^((MOD-1)/(2k)) w_k_base = pow(G, (MOD - 1) // (2 * k), MOD) if inv: # For inverse NTT, use inverse root w_k_base = pow(w_k_base, MOD - 2, MOD) for i in range(0, n, 2 * k): w = 1 # Current power of root of unity for j in range(k): idx1 = i + j idx2 = i + j + k x = a[idx1] y = (a[idx2] * w) % MOD a[idx1] = (x + y) % MOD # Combine a[idx2] = (x - y + MOD) % MOD # Combine w = (w * w_k_base) % MOD # Update root power k *= 2 if inv: # Scale by 1/n for inverse NTT n_inv = pow(n, MOD - 2, MOD) for i in range(n): a[i] = (a[i] * n_inv) % MOD # Function to multiply two polynomials p1, p2 using NTT, result truncated to degree max_deg def multiply_poly(p1, p2, max_deg): len1 = len(p1) len2 = len(p2) # Handle trivial cases (multiplication by 0 or 1) efficiently if len1 == 0 or (len1 == 1 and p1[0] == 0): return [0] * (min(1, max_deg + 1)) if len2 == 0 or (len2 == 1 and p2[0] == 0): return [0] * (min(1, max_deg + 1)) if len1 == 1 and p1[0] == 1: # If p1 is polynomial 1 res = p2[:max_deg+1] # Take p2 up to degree max_deg res.extend([0] * (max_deg + 1 - len(res))) # Pad with zeros if shorter return res if len2 == 1 and p2[0] == 1: # If p2 is polynomial 1 res = p1[:max_deg+1] # Take p1 up to degree max_deg res.extend([0] * (max_deg + 1 - len(res))) # Pad with zeros if shorter return res # Determine required length for NTT (must be power of 2 >= combined degree + 1) needed_len = len1 + len2 - 1 target_len = 1 while target_len < needed_len: target_len <<= 1 # Copy and Pad polynomials with zeros to target_len p1_pad = p1[:] + [0] * (target_len - len1) p2_pad = p2[:] + [0] * (target_len - len2) # Perform forward NTT on both polynomials ntt(p1_pad, False) ntt(p2_pad, False) # Pointwise multiplication in the NTT domain res_pad = [0] * target_len for i in range(target_len): res_pad[i] = (p1_pad[i] * p2_pad[i]) % MOD # Perform inverse NTT to get result polynomial coefficients ntt(res_pad, True) # Truncate the result polynomial to maximum degree `max_deg` (which is K here) final_len = min(max_deg + 1, len(res_pad)) return res_pad[:final_len] # Use a deque to manage polynomials for iterative divide-and-conquer multiplication # This avoids deep recursion stacks for large number of polynomials queue = collections.deque(polys) # Repeatedly multiply pairs of polynomials until only one remains while len(queue) > 1: p1 = queue.popleft() p2 = queue.popleft() # Multiply p1 and p2, keeping result up to degree K res = multiply_poly(p1, p2, K) queue.append(res) # Add result back to queue # The final polynomial P(x) = prod Q_v(x) mod x^(K+1) is the last element in the queue final_poly = queue[0] # Calculate S_leq_K = sum of coefficients of the final polynomial (mod P2) S_leq_K = 0 for coeff in final_poly: S_leq_K = (S_leq_K + coeff) % MOD count = S_leq_K # This sum is the required Count # Calculate the final result R = (term1 - P1 * Count) mod P2 # Ensure P1 is taken modulo P2 before multiplication term2 = ((P1 % MOD) * count) % MOD # Final result calculation, ensuring positive result result = (term1 - term2 + MOD) % MOD print(result) # Execute the main function solve()