結果
| 問題 |
No.1504 ヌメロニム
|
| コンテスト | |
| ユーザー |
qwewe
|
| 提出日時 | 2025-05-14 12:59:24 |
| 言語 | PyPy3 (7.3.15) |
| 結果 |
TLE
|
| 実行時間 | - |
| コード長 | 9,701 bytes |
| コンパイル時間 | 412 ms |
| コンパイル使用メモリ | 82,316 KB |
| 実行使用メモリ | 157,348 KB |
| 最終ジャッジ日時 | 2025-05-14 13:00:39 |
| 合計ジャッジ時間 | 5,922 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge3 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 24 TLE * 1 -- * 36 |
ソースコード
import sys
# Set higher recursion depth if needed, although the iterative NTT should be fine.
# sys.setrecursionlimit(2000)
def solve():
N = int(sys.stdin.readline())
S = sys.stdin.readline().strip()
MOD = 998244353
# --- Utility functions START ---
def fast_pow(base, power):
"""Computes base^power % MOD efficiently using binary exponentiation."""
result = 1
while power > 0:
if power % 2 == 1:
result = (result * base) % MOD
base = (base * base) % MOD
power //= 2
return result
def inverse(a):
"""Computes modular multiplicative inverse using Fermat's Little Theorem.
Assumes MOD is a prime number and a is not divisible by MOD."""
return fast_pow(a, MOD - 2)
# --- Utility functions END ---
# --- NTT implementation START ---
# Use a standard primitive root for MOD 998244353
primitive_root = 3
def ntt(a, is_inverse):
"""Performs Number Theoretic Transform (NTT) in place on list 'a'.
'is_inverse' determines if forward or inverse transform is performed.
Input list 'a' must have length that is a power of 2."""
n = len(a)
if n == 1:
return
# Bit-reversal permutation: arranges elements in the order required for Cooley-Tukey
# This ensures elements accessed in butterfly operations are correctly paired.
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]
# Cooley-Tukey algorithm (iterative version)
k = 1 # Represents half the size of the DFT blocks being merged at the current level
while k < n:
# Calculate the principal N/2k-th root of unity for this level
# This is omega_{2k} = primitive_root ^ ((MOD - 1) / (2*k))
w_len = fast_pow(primitive_root, (MOD - 1) // (2 * k))
if is_inverse:
# For inverse NTT, use the inverse root of unity
w_len = inverse(w_len)
# Iterate through blocks of size 2k
for i in range(0, n, 2 * k):
w = 1 # Current power of the root of unity (omega_{2k}^j)
# Perform butterfly operations within the block [i, i + 2k - 1]
for j in range(k):
# Combine elements from the first half (i+j) and second half (i+j+k)
u = a[i + j]
v = (a[i + j + k] * w) % MOD
# Butterfly operation: DFT[i+j] = DFT_even[j] + omega^j * DFT_odd[j]
# DFT[i+j+k] = DFT_even[j] - omega^j * DFT_odd[j]
a[i + j] = (u + v) % MOD
a[i + j + k] = (u - v + MOD) % MOD # Use + MOD to ensure the result is positive
w = (w * w_len) % MOD # Update to the next power of root of unity
k *= 2 # Move to the next level (double the block size)
# Scale by 1/n if performing inverse NTT
if is_inverse:
inv_n = inverse(n)
for i in range(n):
a[i] = (a[i] * inv_n) % MOD
def multiply(p1, p2):
"""Multiplies two polynomials p1 and p2 represented as lists of coefficients using NTT."""
len1 = len(p1)
len2 = len(p2)
# Determine the size for NTT (must be a power of 2)
# The degree of the result polynomial is (len1-1) + (len2-1). Its length is len1+len2-1.
final_len = len1 + len2 - 1
n = 1
while n < final_len:
n <<= 1 # Find the smallest power of 2 >= final_len
# Pad polynomials with zeros to the required size n
p1_ntt = p1 + [0] * (n - len1)
p2_ntt = p2 + [0] * (n - len2)
# Perform forward NTT on both polynomials
ntt(p1_ntt, False)
ntt(p2_ntt, False)
# Pointwise multiplication in the frequency domain
res_ntt = [(p1_ntt[i] * p2_ntt[i]) % MOD for i in range(n)]
# Perform inverse NTT to get the result polynomial coefficients in the time domain
ntt(res_ntt, True)
# Return the resulting coefficients, truncated to the actual polynomial length
return res_ntt[:final_len]
# --- NTT implementation END ---
# Base case check: Numeronym is defined for strings of length 2 or more.
if N < 2:
print(0) # If N < 2, no subsequences satisfy the condition.
return
# Precompute factorials and their modular inverses up to N.
# Factorials are needed up to N for the second NTT step.
MAX_FAC = N + 1
fact = [1] * MAX_FAC
invfact = [1] * MAX_FAC
for i in range(1, MAX_FAC):
fact[i] = (fact[i - 1] * i) % MOD
# Compute inverse factorial N! first, then compute others using i! = (i+1)! / (i+1)
invfact[MAX_FAC - 1] = inverse(fact[MAX_FAC - 1])
for i in range(MAX_FAC - 2, -1, -1):
invfact[i] = (invfact[i + 1] * (i + 1)) % MOD
# === Step 1: Compute DP[d] using the first NTT ===
# DP[d] is the count of pairs (i, j) such that s_i='i', s_j='n', and j-i-1=d (or j-i=d+1).
# This can be found via convolution of two polynomials derived from S.
# Construct polynomials A'(x) and B'(x) based on positions of 'i' and 'n'.
# A'(x) = sum_{i=1..N} [s_i == 'i'] x^{N-i} (Coefficients represent 'i' positions, reversed)
# B'(x) = sum_{j=1..N} [s_j == 'n'] x^j (Coefficients represent 'n' positions)
# The coefficient of x^k in C'(x) = A'(x)B'(x) gives sum over pairs (i,j) where (N-i)+j = k, i.e., j-i = k-N.
# We need DP[d], which corresponds to j-i=d+1. So we need k-N = d+1, or k = N+d+1.
# DP[d] is the coefficient of x^{N+d+1} in C'(x).
A_coeffs = [0] * N # Represents polynomial derived from 'i' positions, max degree N-1
B_coeffs = [0] * (N + 1) # Represents polynomial derived from 'n' positions, max degree N
# Populate coefficients based on S. Use 0-based indexing for S.
for i in range(N): # Python index i corresponds to 1-based index i+1 in the problem statement
if S[i] == 'i':
# s_{i+1} == 'i', contributes term x^{N-(i+1)} = x^{N-1-i}
A_coeffs[N - 1 - i] = 1
for j in range(N): # Python index j corresponds to 1-based index j+1
if S[j] == 'n':
# s_{j+1} == 'n', contributes term x^{j+1}
B_coeffs[j + 1] = 1
# Compute C'(x) = A'(x) * B'(x) using NTT
C_prime_coeffs = multiply(A_coeffs, B_coeffs)
# Result C'(x) has degree (N-1) + N = 2N-1. Length of coefficient list is 2N.
# Extract DP[d] coefficients. DP[d] = coefficient of x^{N+d+1} in C'(x).
# M is the maximum possible value for k, which is N-2.
M = N - 2
if M < 0: # This case is covered by N < 2 check above, but good to be robust.
print(0)
return
# p[d] stores DP[d]. This is the coefficient list for polynomial P(y) = sum DP[d] * y^d.
p = [0] * (M + 1) # P(y) has degree up to M = N-2
for d in range(M + 1): # d ranges from 0 to N-2
target_idx = N + d + 1 # Index corresponds to exponent N+d+1
# Ensure index is within bounds of the computed coefficients list.
if target_idx < len(C_prime_coeffs):
p[d] = C_prime_coeffs[target_idx]
# If index out of bounds, coefficient is 0, which is the default value in p.
# === Step 2: Compute X_k using the second NTT ===
# X_k = sum_{d=k..M} DP[d] * C(d, k). This corresponds to evaluating P(y) at y=x+1.
# Let Q(x) = P(x+1) = sum q_k x^k. Then q_k = X_k.
# We use a convolution method to compute the coefficients q_k.
# The formula q_k * k! = sum_{i=k..M} (p_i * i!) * (c^{i-k} / (i-k)!) holds. Here c=1.
# q_k * k! = sum_{i=k..M} (p_i * i!) * (1 / (i-k)!)
# Let a_i = p_i * i! and b_j = 1 / j!. We need sum_{i=k..M} a_i * b_{i-k}.
# This is a convolution. Let B_rev(x) = sum b_{M-j} x^j = sum (1 / (M-j)!) x^j.
# The (M+k)-th coefficient of (sum a_i x^i) * B_rev(x) is sum_{i-j'=k} a_i b_{j'}, which is exactly q_k * k!.
# Prepare coefficients for the second convolution
# PolyA(x) = sum a_i x^i where a_i = p_i * i!
a = [0] * (M + 1)
for i in range(M + 1):
a[i] = (p[i] * fact[i]) % MOD
# PolyB(x) = sum b'_j x^j where b'_j = 1 / (M-j)!
b_prime = [0] * (M + 1)
for j in range(M + 1):
b_prime[j] = invfact[M - j] # M-j ranges from M down to 0. Valid indices.
PolyA = a
PolyB = b_prime
# Compute PolyC(x) = PolyA(x) * PolyB(x) using NTT
PolyC_coeffs = multiply(PolyA, PolyB)
# PolyC(x) has degree M + M = 2M. Length of coefficients list is 2M+1.
# Extract X_k values from PolyC_coeffs
# We know q_k * k! = CoefC_{M+k}. So X_k = q_k = CoefC_{M+k} / k! = CoefC_{M+k} * invfact[k].
X = [0] * (M + 1) # Stores values X_0, ..., X_M = X_{N-2}
for k in range(M + 1): # k ranges from 0 to N-2
target_idx = M + k # Index in PolyC_coeffs corresponds to exponent M+k
# Ensure index is within bounds.
if target_idx < len(PolyC_coeffs):
X[k] = (PolyC_coeffs[target_idx] * invfact[k]) % MOD
# If index out of bounds, coefficient is 0, so X[k] remains 0.
# === Step 3: Compute the final XOR sum ===
# Calculate the bitwise XOR sum of all computed X_k values.
final_xor_sum = 0
for k_val in X: # Iterate through the computed values X_0, ..., X_{N-2}
final_xor_sum ^= k_val # Bitwise XOR operation
print(final_xor_sum)
solve()
qwewe