```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)
}
```