結果

問題 No.1195 数え上げを愛したい(文字列編)
ユーザー qwewe
提出日時 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
権限があれば一括ダウンロードができます

ソースコード

diff #

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