← Home
```go
package main

import (
	"bufio"
	"fmt"
	"math/bits"
	"os"
)

const MOD = 998244353
const G = 3

var revCache = map[int][]int{}
var rootCache = map[int]int{}
var irootCache = map[int]int{}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func powMod(a, e int) int {
	res := 1
	x := a
	for e > 0 {
		if e&1 == 1 {
			res = int(int64(res) * int64(x) % MOD)
		}
		x = int(int64(x) * int64(x) % MOD)
		e >>= 1
	}
	return res
}

func getRev(n int) []int {
	if v, ok := revCache[n]; ok {
		return v
	}
	rev := make([]int, n)
	if n > 1 {
		lg := bits.Len(uint(n)) - 1
		for i := 0; i < n; i++ {
			rev[i] = (rev[i>>1] >> 1) | ((i & 1) << (lg - 1))
		}
	}
	revCache[n] = rev
	return rev
}

func getRoot(length int, invert bool) int {
	if invert {
		if v, ok := irootCache[length]; ok {
			return v
		}
		w := powMod(G, (MOD-1)/length)
		w = powMod(w, MOD-2)
		irootCache[length] = w
		return w
	}
	if v, ok := rootCache[length]; ok {
		return v
	}
	w := powMod(G, (MOD-1)/length)
	rootCache[length] = w
	return w
}

func ntt(a []int, invert bool) {
	n := len(a)
	rev := getRev(n)
	for i := 0; i < n; i++ {
		if i < rev[i] {
			a[i], a[rev[i]] = a[rev[i]], a[i]
		}
	}
	for length := 2; length <= n; length <<= 1 {
		wlen := getRoot(length, invert)
		half := length >> 1
		for i := 0; i < n; i += length {
			w := 1
			for j := 0; j < half; j++ {
				u := a[i+j]
				v := int(int64(a[i+j+half]) * int64(w) % MOD)
				a[i+j] = u + v
				if a[i+j] >= MOD {
					a[i+j] -= MOD
				}
				a[i+j+half] = u - v
				if a[i+j+half] < 0 {
					a[i+j+half] += MOD
				}
				w = int(int64(w) * int64(wlen) % MOD)
			}
		}
	}
	if invert {
		ninv := powMod(n, MOD-2)
		for i := 0; i < n; i++ {
			a[i] = int(int64(a[i]) * int64(ninv) % MOD)
		}
	}
}

func convolution(a, b []int) []int {
	if len(a) == 0 || len(b) == 0 {
		return []int{}
	}
	if len(a) < len(b) {
		a, b = b, a
	}
	if len(b) == 1 {
		c := b[0]
		res := make([]int, len(a))
		if c == 0 {
			return res
		}
		for i, v := range a {
			res[i] = int(int64(v) * int64(c) % MOD)
		}
		return res
	}
	if len(b) <= 60 {
		res := make([]int, len(a)+len(b)-1)
		for i, av := range a {
			if av == 0 {
				continue
			}
			for j, bv := range b {
				if bv == 0 {
					continue
				}
				v := res[i+j] + int(int64(av)*int64(bv)%MOD)
				if v >= MOD {
					v -= MOD
				}
				res[i+j] = v
			}
		}
		return res
	}
	need := len(a) + len(b) - 1
	n := 1
	for n < need {
		n <<= 1
	}
	fa := make([]int, n)
	fb := make([]int, n)
	copy(fa, a)
	copy(fb, b)
	ntt(fa, false)
	ntt(fb, false)
	for i := 0; i < n; i++ {
		fa[i] = int(int64(fa[i]) * int64(fb[i]) % MOD)
	}
	ntt(fa, true)
	return fa[:need]
}

func derivative(a []int) []int {
	if len(a) <= 1 {
		return []int{}
	}
	res := make([]int, len(a)-1)
	for i := 1; i < len(a); i++ {
		res[i-1] = int(int64(a[i]) * int64(i) % MOD)
	}
	return res
}

func integral(a []int, n int, invNum []int) []int {
	res := make([]int, n)
	m := len(a)
	if m > n-1 {
		m = n - 1
	}
	for i := 0; i < m; i++ {
		res[i+1] = int(int64(a[i]) * int64(invNum[i+1]) % MOD)
	}
	return res
}

func polyInv(a []int, n int) []int {
	if n == 0 {
		return []int{}
	}
	res := []int{powMod(a[0], MOD-2)}
	for m := 1; m < n; m <<= 1 {
		sz := m << 1
		if sz > n {
			sz = n
		}
		t := convolution(a[:min(len(a), sz)], res)
		if len(t) < sz {
			tmp := make([]int, sz)
			copy(tmp, t)
			t = tmp
		} else {
			t = t[:sz]
		}
		for i := 0; i < sz; i++ {
			if t[i] != 0 {
				t[i] = MOD - t[i]
			}
		}
		t[0] += 2
		if t[0] >= MOD {
			t[0] -= MOD
		}
		res = convolution(res, t)
		if len(res) > sz {
			res = res[:sz]
		}
	}
	if len(res) > n {
		res = res[:n]
	}
	return res
}

func polyLog(a []int, n int, invNum []int) []int {
	if n == 0 {
		return []int{}
	}
	if n == 1 {
		return []int{0}
	}
	da := derivative(a)
	ia := polyInv(a, n)
	prod := convolution(da, ia)
	if len(prod) > n-1 {
		prod = prod[:n-1]
	}
	return integral(prod, n, invNum)
}

func solveSeries(n int, invNum []int) []int {
	target := n + 1
	res := make([]int, min(2, target))
	res[0] = 1
	if target > 1 {
		res[1] = 1
	}
	cur := len(res)
	for cur < target {
		nxt := cur << 1
		if nxt > target {
			nxt = target
		}
		ln := polyLog(res, nxt, invNum)
		f := make([]int, nxt)
		for i := 0; i < nxt; i++ {
			v := 0
			if i < len(ln) {
				v = ln[i] + ln[i]
				if v >= MOD {
					v -= MOD
				}
			}
			if i < len(res) {
				v -= res[i]
				if v < 0 {
					v += MOD
				}
			}
			f[i] = v
		}
		f[0]++
		if f[0] >= MOD {
			f[0] -= MOD
		}
		if nxt > 1 {
			f[1]--
			if f[1] < 0 {
				f[1] += MOD
			}
		}
		twoMinus := make([]int, nxt)
		twoMinus[0] = 2
		for i := 0; i < len(res) && i < nxt; i++ {
			twoMinus[i] -= res[i]
			if twoMinus[i] < 0 {
				twoMinus[i] += MOD
			}
		}
		invDen := polyInv(twoMinus, nxt)
		mult := convolution(res, invDen)
		if len(mult) > nxt {
			mult = mult[:nxt]
		}
		corr := convolution(f, mult)
		if len(corr) > nxt {
			corr = corr[:nxt]
		}
		newRes := make([]int, nxt)
		for i := 0; i < nxt; i++ {
			v := 0
			if i < len(res) {
				v = res[i]
			}
			v -= corr[i]
			if v < 0 {
				v += MOD
			}
			newRes[i] = v
		}
		res = newRes
		cur = nxt
	}
	return res
}

func main() {
	in := bufio.NewReaderSize(os.Stdin, 1<<20)
	out := bufio.NewWriterSize(os.Stdout, 1<<20)
	defer out.Flush()

	var n int
	fmt.Fscan(in, &n)

	invNum := make([]int, n+2)
	invNum[1] = 1
	for i := 2; i < len(invNum); i++ {
		invNum[i] = MOD - int(int64(MOD/i)*int64(invNum[MOD%i])%MOD)
	}

	series := solveSeries(n, invNum)

	fact := 1
	for i := 1; i <= n; i++ {
		fact = int(int64(fact) * int64(i) % MOD)
	}

	ans := int(int64(series[n]) * int64(fact) % MOD)
	ans -= 2
	if ans < 0 {
		ans += MOD
	}
	fmt.Fprintln(out, ans)
}
```