結果
問題 |
No.2959 Dolls' Tea Party
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:18:42 |
言語 | PyPy3 (7.3.15) |
結果 |
TLE
|
実行時間 | - |
コード長 | 11,176 bytes |
コンパイル時間 | 171 ms |
コンパイル使用メモリ | 82,740 KB |
実行使用メモリ | 173,800 KB |
最終ジャッジ日時 | 2025-05-14 13:19:38 |
合計ジャッジ時間 | 5,534 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 4 |
other | AC * 2 TLE * 1 -- * 30 |
ソースコード
import sys # Increase recursion depth for deep polynomial operations if necessary # sys.setrecursionlimit(2000) def solve(): N, K = map(int, sys.stdin.readline().split()) A = list(map(int, sys.stdin.readline().split())) MOD = 998244353 # Precompute factorials, inverse factorials, and modular inverses # Need values up to K+1 because integration involves division by k+1 where k can be up to K MAX_K = K + 2 fact = [1] * MAX_K inv_fact = [1] * MAX_K inv = [1] * MAX_K for i in range(1, MAX_K): fact[i] = (fact[i-1] * i) % MOD # Compute inverse factorial of MAX_K-1 using Fermat's Little Theorem inv_fact[MAX_K-1] = pow(fact[MAX_K-1], MOD - 2, MOD) # Compute inverse factorials downwards for i in range(MAX_K - 2, -1, -1): inv_fact[i] = (inv_fact[i+1] * (i+1)) % MOD # Compute modular inverses using inverse factorials # inv[i] = i^{-1} mod MOD = (i-1)! * (i!)^{-1} mod MOD for i in range(1, MAX_K): inv[i] = (inv_fact[i] * fact[i-1]) % MOD # Technically inv[0] is undefined, set to 0 for safety though not used meaningfully inv[0] = 0 # NTT implementation G = 3 # Primitive root for MOD = 998244353 def ntt(a, is_inverse): """ Performs Number Theoretic Transform (NTT) in place. """ n = len(a) # 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] # Cooley-Tukey algorithm k = 1 while k < n: # Twiddle factor step w_step = pow(G, (MOD - 1) // (2 * k), MOD) if is_inverse: # Use inverse root for inverse NTT w_step = pow(w_step, MOD - 2, MOD) for i in range(0, n, 2 * k): w = 1 # Current twiddle factor omega^j for j in range(i, i + k): u = a[j] v = (a[j + k] * w) % MOD a[j] = (u + v) % MOD a[j + k] = (u - v + MOD) % MOD w = (w * w_step) % MOD # Update twiddle factor k *= 2 if is_inverse: # Divide by n for inverse transform n_inv = pow(n, MOD - 2, MOD) for i in range(n): a[i] = (a[i] * n_inv) % MOD return a def poly_mul(p1, p2, target_len): """ Multiplies two polynomials p1 and p2 using NTT, returns result truncated to target_len. """ len1 = len(p1) len2 = len(p2) if len1 == 0 or len2 == 0: return [0] * target_len # Determine required NTT length (power of 2 >= final degree + 1) n = 1 while n < len1 + len2 - 1: n <<= 1 # Pad polynomials to length n p1_ntt = p1 + [0] * (n - len1) p2_ntt = p2 + [0] * (n - len2) # Perform NTT on both polynomials ntt(p1_ntt, False) ntt(p2_ntt, False) # Pointwise multiplication in frequency domain res_ntt = [(p1_ntt[i] * p2_ntt[i]) % MOD for i in range(n)] # Inverse NTT to get result in coefficient domain ntt(res_ntt, True) # Return result truncated to target_len return res_ntt[:target_len] def poly_inv(p, target_len): """ Computes modular inverse of polynomial p modulo x^target_len using Newton-Raphson. """ if target_len == 0: return [] # Pad p to target_len to avoid index errors and ensure consistency p_eff = p[:target_len] + [0]*(target_len - len(p)) if target_len == 1: # Base case: inverse of constant term if not p_eff or p_eff[0] == 0: raise ValueError("Polynomial has no inverse (constant term is 0)") return [pow(p_eff[0], MOD - 2, MOD)] # Recursive step: find inverse mod x^k first k = (target_len + 1) // 2 inv_k = poly_inv(p, k) # Recursive call with original p, length k # Determine NTT length n = 1 while n < target_len + k -1: # Needs length at least target_len for result, and involves P up to target_len n <<= 1 # Prepare P and Inv_k for NTT p_ntt = p_eff[:target_len] + [0] * (n - target_len) inv_k_ntt = inv_k + [0] * (n - len(inv_k)) ntt(p_ntt, False) ntt(inv_k_ntt, False) # Compute P * Inv_k mod x^target_len pk_ik_ntt = [(p_ntt[i] * inv_k_ntt[i]) % MOD for i in range(n)] ntt(pk_ik_ntt, True) pk_ik = pk_ik_ntt[:target_len] # Newton-Raphson update step: Calculate 2 - P * Inv_k mod x^target_len res_poly = [0] * target_len res_poly[0] = 2 for i in range(target_len): res_poly[i] = (res_poly[i] - pk_ik[i] + MOD) % MOD # Transform (2 - P*Inv_k) to frequency domain res_poly_ntt = res_poly + [0] * (n - target_len) ntt(res_poly_ntt, False) # Multiply Inv_k * (2 - P * Inv_k) in frequency domain final_res_ntt = [(inv_k_ntt[i] * res_poly_ntt[i]) % MOD for i in range(n)] # Transform back to coefficient domain ntt(final_res_ntt, True) return final_res_ntt[:target_len] def poly_deriv(p): """ Computes the derivative of polynomial p. """ if len(p) <= 1: return [] res = [0] * (len(p) - 1) for i in range(1, len(p)): res[i-1] = (p[i] * i) % MOD return res def poly_integr(p): """ Computes the integral of polynomial p (constant term 0). """ res = [0] * (len(p) + 1) for i in range(len(p)): # Needs inv[i+1] precomputed res[i+1] = (p[i] * inv[i+1]) % MOD return res def poly_log(p, target_len): """ Computes logarithm ln(P(x)) mod x^target_len. Requires P(0)=1. """ # Pad p to target_len for internal calculations p_eff = p[:target_len] + [0]*(target_len - len(p)) # Check prerequisite P(0)=1 if not p_eff or p_eff[0] != 1: raise ValueError(f"Logarithm undefined for polynomial not starting with 1. P[0]={p_eff[0] if p_eff else 'empty'}") if target_len == 1: return [0] # log(1) = 0 # Compute P'(x) p_deriv = poly_deriv(p_eff) # Compute P(x)^{-1} mod x^target_len p_inv = poly_inv(p_eff, target_len) # Compute P'(x) * P(x)^{-1} mod x^target_len prod = poly_mul(p_deriv, p_inv, target_len) # Integrate the product. Integration needs terms up to x^(target_len-2) to get result up to x^(target_len-1). # Integral of Prod[k] * x^k is Prod[k]/(k+1) * x^(k+1). res = poly_integr(prod[:target_len-1]) return res[:target_len] def poly_exp(q, target_len): """ Computes exponentiation exp(Q(x)) mod x^target_len. Requires Q(0)=0. """ # Pad q to target_len q_eff = q[:target_len] + [0]*(target_len - len(q)) # Check prerequisite Q(0)=0 if not q_eff or q_eff[0] != 0: raise ValueError(f"Exponentiation undefined for polynomial not starting with 0. Q[0]={q_eff[0] if q_eff else 'empty'}") if target_len == 1: return [1] # exp(0) = 1 # Recursive step: find exp(Q) mod x^k first k = (target_len + 1) // 2 exp_k = poly_exp(q_eff, k) # Recursive call with q_eff, length k # Compute ln(exp(Q)_k) mod x^target_len. exp_k has length k. log_exp_k = poly_log(exp_k, target_len) # Pass exp_k directly, poly_log handles padding # Newton-Raphson update: Compute 1 + Q - ln(Exp_k) mod x^target_len res_poly = [0] * target_len res_poly[0] = 1 # Add Q for i in range(target_len): res_poly[i] = (res_poly[i] + q_eff[i]) % MOD # Subtract ln(Exp_k) for i in range(target_len): res_poly[i] = (res_poly[i] - log_exp_k[i] + MOD) % MOD # Multiply Exp_k * (1 + Q - ln(Exp_k)) mod x^target_len final_res = poly_mul(exp_k, res_poly, target_len) return final_res[:target_len] # Euler totient function calculation phi_map = {} def get_phi(m): """ Computes Euler's totient function phi(m), uses caching. """ if m in phi_map: return phi_map[m] if m == 0: return 0 if m == 1: phi_map[1] = 1; return 1 res = m p = 2 temp_m = m while p * p <= temp_m: if temp_m % p == 0: res = res // p * (p - 1) while temp_m % p == 0: temp_m //= p p += 1 if temp_m > 1: # If temp_m is still > 1, it must be a prime factor res = res // temp_m * (temp_m - 1) phi_map[m] = res return res # Find all divisors of K divisors = [] for i in range(1, int(K**0.5) + 1): if K % i == 0: divisors.append(i) if i*i != K: divisors.append(K//i) divisors.sort() # Main logic using Burnside's Lemma total_S = 0 # Sum of |X^g| terms for d in divisors: L = K // d # Cycle length # Group doll types by B_i = floor(A_i / L) value counts = {} # counts[b] = number of types i with B_i = b for x in A: Bi = x // L if Bi > 0: # Only types that can form at least one cycle matter counts[Bi] = counts.get(Bi, 0) + 1 # Calculate Sum_{b} C_b * ln(P_b(x)) where P_b(x) = sum_{k=0..b} x^k/k! sum_log_Pb = [0] * (d + 1) # Target length is d+1 for degree d polynomial for b, count in counts.items(): if count == 0: continue # Skip if count is zero # Construct P_b(x) = sum_{k=0..b} x^k / k! up to degree d Pb = [0] * (d + 1) for k in range(min(b, d) + 1): # Fill coefficients up to degree min(b, d) Pb[k] = inv_fact[k] # Compute log(P_b(x)) mod x^(d+1) log_Pb = poly_log(Pb, d + 1) # Add C_b * log(P_b(x)) to the total log sum for i in range(d + 1): sum_log_Pb[i] = (sum_log_Pb[i] + count * log_Pb[i]) % MOD # Compute F(x) = exp(sum_log_Pb) mod x^(d+1) # F(x) = Product_{i=1..N} P_{B_i}(x) = Product_b P_b(x)^{C_b} F = poly_exp(sum_log_Pb, d + 1) # Extract coefficient [x^d] F(x) coeff_d = F[d] if d < len(F) else 0 # Compute S_d = d! * [x^d] F(x) / d! = d! * coeff_d Sd = (fact[d] * coeff_d) % MOD # Calculate phi(K/d) phi_val = get_phi(K // d) # Add contribution phi(K/d) * S_d to the total sum total_S = (total_S + phi_val * Sd) % MOD # Final answer is (1/K) * total_S mod MOD K_inv = pow(K, MOD - 2, MOD) final_ans = (total_S * K_inv) % MOD print(final_ans) solve()