結果
問題 |
No.1195 数え上げを愛したい(文字列編)
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:11:38 |
言語 | PyPy3 (7.3.15) |
結果 |
TLE
|
実行時間 | - |
コード長 | 8,141 bytes |
コンパイル時間 | 155 ms |
コンパイル使用メモリ | 82,652 KB |
実行使用メモリ | 274,364 KB |
最終ジャッジ日時 | 2025-05-14 13:13:28 |
合計ジャッジ時間 | 8,785 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | TLE * 1 -- * 25 |
ソースコード
import sys # Fast I/O for reading input def input(): return sys.stdin.readline().strip() # Define the modulus MOD = 998244353 # Precompute factorials and inverse factorials up to the maximum possible length of S # The problem states |S| <= 3 * 10^5 MAX_N_precompute = 3 * 10**5 # Initialize lists for factorials and inverse factorials fact = [1] * (MAX_N_precompute + 1) inv_fact = [1] * (MAX_N_precompute + 1) def precompute_factorials(max_val): """ Precomputes factorials and inverse factorials modulo MOD up to max_val. """ # Compute factorials: fact[i] = i! mod MOD for i in range(1, max_val + 1): fact[i] = (fact[i-1] * i) % MOD # Compute inverse factorial of max_val using modular exponentiation (Fermat's Little Theorem) # inv_fact[max_val] = (max_val!)^(MOD-2) mod MOD inv_fact[max_val] = pow(fact[max_val], MOD - 2, MOD) # Compute inverse factorials downwards using the relation (k!)^{-1} = ((k+1)! )^{-1} * (k+1) # This is more efficient than computing modular inverse for each k. for i in range(max_val - 1, -1, -1): inv_fact[i] = (inv_fact[i+1] * (i+1)) % MOD # Call precomputation once with the maximum possible |S| precompute_factorials(MAX_N_precompute) # Iterative NTT (Number Theoretic Transform) implementation # Based on standard Cooley-Tukey FFT algorithm adapted for modular arithmetic def ntt_internal(a, inv): """ Performs NTT or Inverse NTT on the list `a`. `inv` flag indicates if Inverse NTT is needed. The list `a` is modified in-place. Returns the transformed list. """ n = len(a) if n == 1: return a # Bit-reversal permutation: rearrange elements to the order required by iterative FFT # This ensures elements that combine in butterflies are adjacent at appropriate stages. j = 0 for i in range(1, n): bit = n >> 1 while j & bit: j ^= bit bit >>= 1 j ^= bit if i < j: a[i], a[j] = a[j], a[i] # Main Cooley-Tukey butterfly loops len_ = 2 # Current transform size (block size) while len_ <= n: # Calculate the principal len_-th root of unity modulo MOD # Using primitive root 3 for MOD = 998244353 wlen = pow(3, (MOD - 1) // len_, MOD) if inv: # For inverse NTT, use the modular inverse of the root of unity wlen = pow(wlen, MOD - 2, MOD) # Iterate through blocks of size len_ i = 0 while i < n: w = 1 # Current power of the root of unity wlen # Perform butterfly operations within the block for k in range(len_ // 2): # Standard butterfly operation: # u = a[i+k], v = a[i+k+len_/2] * w^k # a[i+k] = u + v # a[i+k+len_/2] = u - v u = a[i + k] v = (a[i + k + len_ // 2] * w) % MOD a[i + k] = (u + v) % MOD a[i + k + len_ // 2] = (u - v + MOD) % MOD # Add MOD to ensure result is non-negative w = (w * wlen) % MOD # Update root power for next iteration i += len_ # Move to the next block len_ <<= 1 # Double the block size for the next level # If performing inverse NTT, divide all resulting coefficients by n (modulo MOD) if inv: n_inv = pow(n, MOD - 2, MOD) # Modular inverse of n for i in range(n): a[i] = (a[i] * n_inv) % MOD return a # Polynomial multiplication using NTT def poly_mult(a, b): """ Multiplies two polynomials represented by coefficient lists `a` and `b` using NTT. Returns the coefficient list of the product polynomial. """ len_a = len(a) len_b = len(b) # Calculate the length required for the result polynomial coefficient list # Degree of product is (len_a - 1) + (len_b - 1) = len_a + len_b - 2 # Number of coefficients is (degree + 1) = len_a + len_b - 1 res_len = len_a + len_b - 1 # Determine the NTT size: smallest power of 2 >= res_len n = 1 while n < res_len: n <<= 1 # Pad the coefficient lists with zeros to match the NTT size n a_pad = a + [0] * (n - len_a) b_pad = b + [0] * (n - len_b) # Compute forward NTT for both polynomials # ntt_internal modifies lists in-place, so pass copies if needed, though here it's fine. a_ntt = ntt_internal(a_pad, False) b_ntt = ntt_internal(b_pad, False) # Perform pointwise multiplication in the frequency domain c_ntt = [0] * n for i in range(n): c_ntt[i] = (a_ntt[i] * b_ntt[i]) % MOD # Compute inverse NTT to get the coefficients of the product polynomial c = ntt_internal(c_ntt, True) # Return the resulting coefficients, truncated to the actual required length (res_len) return c[:res_len] # Main logic to solve the problem def solve(): """ Reads input string S, calculates the number of distinct strings formed by rearranging subsets of its characters (at least one character), and prints the result modulo MOD. """ S = input() N = len(S) # Length of the input string S # Count frequencies of each character in S using a dictionary counts = {} for char in S: counts[char] = counts.get(char, 0) + 1 # Get the list of counts for distinct characters present in S distinct_counts = list(counts.values()) # Initialize the polynomial P(x) representing the overall Exponential Generating Function (EGF). # Start with P(x) = 1 (coefficient list [1]), representing the base case (using an empty set of characters). # The coefficient of x^j / j! in P(x) will represent the sum of ways to form strings of length j. current_poly_coeffs = [1] # Iteratively multiply the current EGF polynomial P(x) by the EGF for each distinct character count for count_Ni in distinct_counts: # Construct the polynomial A_i(x) for the current character count N_i. # This polynomial represents the EGF for choosing k characters of this type (0 <= k <= N_i). # A_i(x) = sum_{k=0}^{N_i} (1/k!) * x^k # The coefficients are [1/0!, 1/1!, ..., 1/N_i!] obtained from precomputed inverse factorials. poly_Ai_coeffs = [inv_fact[k] for k in range(count_Ni + 1)] # Multiply the current overall EGF polynomial P(x) by A_i(x) using NTT based polynomial multiplication. # The result updates P(x) to include combinations with the current character type. current_poly_coeffs = poly_mult(current_poly_coeffs, poly_Ai_coeffs) # Prune the resulting polynomial: the maximum length of strings formed is N = |S|. # The polynomial degree cannot exceed N. If the resulting polynomial has degree > N (length > N+1), # trim the coefficients corresponding to degrees greater than N. if len(current_poly_coeffs) > N + 1: current_poly_coeffs = current_poly_coeffs[:N+1] # After processing all distinct characters, `current_poly_coeffs` holds the coefficients p_j of the final EGF P(x). # P(x) = sum_{j=0}^{N} p_j x^j, where p_j = dp(m, j) / j! # dp(m, j) is the sum of multinomial coefficients corresponding to strings of length j. final_coeffs = current_poly_coeffs # Calculate the final answer: sum of dp(m, j) for j = 1 to N. # We need strings formed by at least one character, so sum starts from j=1. total_sum = 0 # Iterate through possible string lengths j from 1 up to N. # The loop upper bound must respect the actual length of `final_coeffs`. max_j = min(N, len(final_coeffs) - 1) # Max index is len - 1 for j in range(1, max_j + 1): # Get the coefficient p_j = final_coeffs[j] # Compute dp(m, j) = p_j * j! using precomputed factorials dp_m_j = (final_coeffs[j] * fact[j]) % MOD # Add dp(m, j) to the total sum modulo MOD total_sum = (total_sum + dp_m_j) % MOD # Print the final result print(total_sum) # Execute the solver function solve()