defconv_mod_fft(a: np.ndarray, b: np.ndarray) -> np.ndarray: na = a.size nb = b.size if na == 0or nb == 0: return np.zeros(0, dtype=np.int64) need = na + nb - 1 L = 1 << ((need - 1).bit_length()) base = 1 << 15
a = a.astype(np.int64, copy=False) % MOD b = b.astype(np.int64, copy=False) % MOD
c00 = np.rint(c00).astype(np.int64) % MOD c01 = np.rint(c01).astype(np.int64) % MOD c11 = np.rint(c11).astype(np.int64) % MOD
bb = base % MOD bb2 = (base * base) % MOD return (c00 + c01 * bb + c11 * bb2) % MOD
defpoly_mul(a: np.ndarray, b: np.ndarray, lim: int) -> np.ndarray: if lim <= 0: return np.zeros(0, dtype=np.int64) if a.size == 0or b.size == 0: return np.zeros(lim, dtype=np.int64) if a.size * b.size <= 4000: L = min(lim, a.size + b.size - 1) r = np.zeros(L, dtype=np.int64) aa = a.astype(np.int64, copy=False) % MOD bb = b.astype(np.int64, copy=False) % MOD for i inrange(aa.size): ai = int(aa[i]) if ai == 0: continue jmax = min(bb.size, L - i) if jmax > 0: r[i:i + jmax] = (r[i:i + jmax] + ai * bb[:jmax]) % MOD if L < lim: r = np.pad(r, (0, lim - L)) return r[:lim] c = conv_mod_fft(a, b) if c.size < lim: c = np.pad(c, (0, lim - c.size)) return c[:lim]
defpoly_inv(f: np.ndarray, m: int) -> np.ndarray: g = np.array([pow(int(f[0]), MOD - 2, MOD)], dtype=np.int64) n = 1 while n < m: n2 = min(2 * n, m) fg = poly_mul(f[:n2], g, n2) t = np.zeros(n2, dtype=np.int64) t[0] = (2 - fg[0]) % MOD if n2 > 1: t[1:] = (-fg[1:]) % MOD g = poly_mul(g, t, n2) n = n2 return g[:m]
defpoly_log(f: np.ndarray, m: int, inv: np.ndarray) -> np.ndarray: df = np.zeros(max(0, m - 1), dtype=np.int64) up = min(f.size, m) if up > 1: idx = np.arange(1, up, dtype=np.int64) df[:up - 1] = (f[1:up] * idx) % MOD invf = poly_inv(f, m) q = poly_mul(df, invf, m - 1) res = np.zeros(m, dtype=np.int64) if m > 1: res[1:] = (q[:m - 1] * inv[1:m]) % MOD return res
defpoly_exp(a: np.ndarray, m: int, inv: np.ndarray) -> np.ndarray: f = np.array([1], dtype=np.int64) n = 1 while n < m: n2 = min(2 * n, m) ln_f = poly_log(f, n2, inv) diff = (a[:n2] - ln_f) % MOD diff[0] = (diff[0] + 1) % MOD f = poly_mul(f, diff, n2) n = n2 return f[:m]
defsolve(N): inv = np.zeros(N + 1, dtype=np.int64) inv[1] = 1 for i inrange(2, N + 1): inv[i] = (MOD - (MOD // i) * inv[MOD % i] % MOD) % MOD
spf = Factorizer(N).spf D = [0] * (N + 1) D[1] = 1 for x inrange(2, N + 1): t = x res = 0 while t > 1: p = spf[t] e = 0 while t % p == 0: t //= p e += 1 res += e * (x // p) D[x] = res % MOD
L = np.zeros(N + 1, dtype=np.int64) for k inrange(1, N + 1): ak = D[k] % MOD if ak == 0: continue pw = ak lim = N // k for m inrange(1, lim + 1): L[k * m] = (L[k * m] + pw * inv[m]) % MOD pw = (pw * ak) % MOD
f = poly_exp(L, N + 1, inv) ans = int(f[1:].sum() % MOD) return ans