← Home
```go
package main

import (
	"bufio"
	"os"
)

const MOD int64 = 998244353

type FastScanner struct {
	r *bufio.Reader
}

func NewFastScanner() *FastScanner {
	return &FastScanner{r: bufio.NewReader(os.Stdin)}
}

func (fs *FastScanner) NextInt() int {
	sign := 1
	val := 0
	b, _ := fs.r.ReadByte()
	for (b < '0' || b > '9') && b != '-' {
		b, _ = fs.r.ReadByte()
	}
	if b == '-' {
		sign = -1
		b, _ = fs.r.ReadByte()
	}
	for b >= '0' && b <= '9' {
		val = val*10 + int(b-'0')
		b, _ = fs.r.ReadByte()
	}
	return val * sign
}

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

func precomputeFacts(n int) ([]int64, []int64) {
	fact := make([]int64, n+1)
	ifact := make([]int64, n+1)
	fact[0] = 1
	for i := 1; i <= n; i++ {
		fact[i] = fact[i-1] * int64(i) % MOD
	}
	ifact[n] = modPow(fact[n], MOD-2)
	for i := n - 1; i >= 0; i-- {
		ifact[i] = ifact[i+1] * int64(i+1) % MOD
	}
	return fact, ifact
}

func perm(fact, ifact []int64, n, k int) int64 {
	if k < 0 || k > n {
		return 0
	}
	return fact[n] * ifact[n-k] % MOD
}

func countMatchings(allowed []bool) []int64 {
	n := len(allowed)
	K := n / 2
	prev2 := make([]int64, K+1)
	prev := make([]int64, K+1)
	prev[0] = 1
	for i := 1; i <= n; i++ {
		cur := make([]int64, K+1)
		if !allowed[i-1] {
			for k := 0; k <= K; k++ {
				cur[k] = prev[k]
			}
		} else {
			for k := 0; k <= K; k++ {
				cur[k] = prev[k]
			}
			if i >= 2 && allowed[i-2] {
				for k := 1; k <= K; k++ {
					cur[k] += prev2[k-1]
					if cur[k] >= MOD {
						cur[k] -= MOD
					}
				}
			}
		}
		prev2, prev = prev, cur
	}
	return prev
}

func main() {
	in := NewFastScanner()
	h := in.NextInt()
	w := in.NextInt()
	n := in.NextInt()

	rowUsed := make([]bool, h)
	colUsed := make([]bool, w)

	for i := 0; i < n; i++ {
		r1 := in.NextInt()
		c1 := in.NextInt()
		r2 := in.NextInt()
		c2 := in.NextInt()
		r1--
		c1--
		r2--
		c2--
		if r1 == r2 {
			rowUsed[r1] = true
			colUsed[c1] = true
			colUsed[c2] = true
		} else {
			colUsed[c1] = true
			rowUsed[r1] = true
			rowUsed[r2] = true
		}
	}

	allowedRow := make([]bool, h)
	allowedCol := make([]bool, w)
	rfree := 0
	cfree := 0
	for i := 0; i < h; i++ {
		if !rowUsed[i] {
			allowedRow[i] = true
			rfree++
		}
	}
	for j := 0; j < w; j++ {
		if !colUsed[j] {
			allowedCol[j] = true
			cfree++
		}
	}

	dpR := countMatchings(allowedRow)
	dpC := countMatchings(allowedCol)

	lim := h
	if w > lim {
		lim = w
	}
	fact, ifact := precomputeFacts(lim)

	ans := int64(0)
	maxAv := len(dpR) - 1
	maxAh := len(dpC) - 1
	for av := 0; av <= maxAv; av++ {
		if dpR[av] == 0 {
			continue
		}
		nr := rfree - 2*av
		if nr < 0 {
			continue
		}
		for ah := 0; ah <= maxAh; ah++ {
			if dpC[ah] == 0 {
				continue
			}
			if nr < ah {
				continue
			}
			nc := cfree - 2*ah
			if nc < av {
				continue
			}
			ways := dpC[ah]
			ways = ways * dpR[av] % MOD
			ways = ways * perm(fact, ifact, nr, ah) % MOD
			ways = ways * perm(fact, ifact, nc, av) % MOD
			ans += ways
			if ans >= MOD {
				ans -= MOD
			}
		}
	}

	out := bufio.NewWriter(os.Stdout)
	out.WriteString(intToString(ans))
	out.WriteByte('\n')
	out.Flush()
}

func intToString(x int64) string {
	if x == 0 {
		return "0"
	}
	var buf [32]byte
	pos := len(buf)
	neg := false
	if x < 0 {
		neg = true
		x = -x
	}
	for x > 0 {
		pos--
		buf[pos] = byte('0' + x%10)
		x /= 10
	}
	if neg {
		pos--
		buf[pos] = '-'
	}
	return string(buf[pos:])
}
```