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