Buggy python submission (verdict: Time Limit Exceeded):
def d_double_landxcape(N, M, A, B):
    """
    N行M列のグリッドに1からNMまでの整数を重複なく書き込む。このとき、以下の条件を満たす。
    ・i行目に書き込まれている値のうち、最大の値はA_i
    ・j行目に書き込まれている値のうち、最大の値はA_j
    書き込み方の総数を10**9+7で割った余りを求めよ。
    """

    # Aの各要素、またはBの各要素の中で、同じ値があるならば解は0
    # (異なる行/列に同じ数字を書き込むことは不可能)。
    # グリッドの中のxが書かれうる場所について、xが大きな順に考える。

    # 1. xがA_iとB_jの両方に現れる場合
    # xの場所は一意に定まる。

    # 2. xがA_iとB_jの片方に現れる場合
    # xがA_iに現れている場合、xの場所としてありうるものの個数は、
    # (B_j >= x となるjの個数) である。
    # xはA_i行にしか書き込めないし、B_j < x となる列に書き込むと
    # 矛盾してしまうため。

    # 3. xがAにもBにも現れない場合
    # xの場所としてありうるものの個数は、
    # (A_i >= x となるiの個数) * (B_j >= x となるjの個数) である。
    # ただし、そのうち NM - x 個はxより大きな値が書き込まれている。

    # 以上の値の総乗が解である。
    from bisect import bisect_left

    a = sorted(A)
    b = sorted(B)
    a_set = set(A)
    b_set = set(B)
    if len(a) != len(a_set) or len(b) != len(b_set):
        return 0  # 重複する要素があった。矛盾する。

    ans = 1
    for k in range(N * M, 0, -1):
        cond1 = k in a_set
        cond2 = k in b_set
        # 順に、上にコメントした、条件1. 2. 3. を満たす場合
        if cond1 and cond2:
            continue
        elif cond1:
            idx = bisect_left(b, k)
            ans *= (M - idx)
        elif cond2:
            idx = bisect_left(a, k)
            ans *= (N - idx)
        else:
            idx_a = bisect_left(a, k)
            idx_b = bisect_left(b, k)
            ans *= (N - idx_a) * (M - idx_b) - (N * M - k)
    return ans % (10**9 + 7)

N, M = [int(i) for i in input().split()]
A = [int(i) for i in input().split()]
B = [int(i) for i in input().split()]
print(d_double_landxcape(N, M, A, B))

Fixed submission:
def d_double_landxcape(N, M, A, B):
    """
    N行M列のグリッドに1からNMまでの整数を重複なく書き込む。このとき、以下の条件を満たす。
    ・i行目に書き込まれている値のうち、最大の値はA_i
    ・j行目に書き込まれている値のうち、最大の値はA_j
    書き込み方の総数を10**9+7で割った余りを求めよ。
    """

    # Aの各要素、またはBの各要素の中で、同じ値があるならば解は0
    # (異なる行/列に同じ数字を書き込むことは不可能)。
    # グリッドの中のxが書かれうる場所について、xが大きな順に考える。

    # 1. xがA_iとB_jの両方に現れる場合
    # xの場所は一意に定まる。

    # 2. xがA_iとB_jの片方に現れる場合
    # xがA_iに現れている場合、xの場所としてありうるものの個数は、
    # (B_j >= x となるjの個数) である。
    # xはA_i行にしか書き込めないし、B_j < x となる列に書き込むと
    # 矛盾してしまうため。

    # 3. xがAにもBにも現れない場合
    # xの場所としてありうるものの個数は、
    # (A_i >= x となるiの個数) * (B_j >= x となるjの個数) である。
    # ただし、そのうち NM - x 個はxより大きな値が書き込まれている。

    # 以上の値の総乗が解である。
    from bisect import bisect_left
    MOD = 10**9 + 7

    a = sorted(A)
    b = sorted(B)
    a_set = set(A)
    b_set = set(B)
    if len(a) != len(a_set) or len(b) != len(b_set):
        return 0  # 重複する要素があった。矛盾する。

    ans = 1
    for k in range(N * M, 0, -1):
        cond1 = k in a_set
        cond2 = k in b_set
        # 順に、上にコメントした、条件1. 2. 3. を満たす場合
        if cond1 and cond2:
            continue
        elif cond1:
            idx = bisect_left(b, k)
            ans *= (M - idx)
        elif cond2:
            idx = bisect_left(a, k)
            ans *= (N - idx)
        else:
            idx_a = bisect_left(a, k)
            idx_b = bisect_left(b, k)
            ans *= (N - idx_a) * (M - idx_b) - (N * M - k)
        ans %= MOD
    return ans % MOD

N, M = [int(i) for i in input().split()]
A = [int(i) for i in input().split()]
B = [int(i) for i in input().split()]
print(d_double_landxcape(N, M, A, B))

Buggy python submission (verdict: Time Limit Exceeded):
def d_double_landxcape(N, M, A, B):
    """
    N行M列のグリッドに1からNMまでの整数を重複なく書き込む。このとき、以下の条件を満たす。
    ・i行目に書き込まれている値のうち、最大の値はA_i
    ・j行目に書き込まれている値のうち、最大の値はA_j
    書き込み方の総数を10**9+7で割った余りを求めよ。
    """

    # Aの各要素、またはBの各要素の中で、同じ値があるならば解は0
    # (異なる行/列に同じ数字を書き込むことは不可能)。
    # グリッドの中のxが書かれうる場所について、xが大きな順に考える。

    # 1. xがA_iとB_jの両方に現れる場合
    # xの場所は一意に定まる。

    # 2. xがA_iとB_jの片方に現れる場合
    # xがA_iに現れている場合、xの場所としてありうるものの個数は、
    # (B_j >= x となるjの個数) である。
    # xはA_i行にしか書き込めないし、B_j < x となる列に書き込むと
    # 矛盾してしまうため。

    # 3. xがAにもBにも現れない場合
    # xの場所としてありうるものの個数は、
    # (A_i >= x となるiの個数) * (B_j >= x となるjの個数) である。
    # ただし、そのうち NM - x 個はxより大きな値が書き込まれている。

    # 以上の値の総乗が解である。
    from bisect import bisect_left

    a = sorted(A)
    b = sorted(B)
    a_set = set(A)
    b_set = set(B)
    if len(a) != len(a_set) or len(b) != len(b_set):
        return 0  # 重複する要素があった。矛盾する。

    ans = 1
    for k in range(N * M, 0, -1):
        cond1 = k in a_set
        cond2 = k in b_set
        # 順に、上にコメントした、条件1. 2. 3. を満たす場合
        if cond1 and cond2:
            continue
        elif cond1:
            idx = bisect_left(b, k)
            ans *= (M - idx)
        elif cond2:
            idx = bisect_left(a, k)
            ans *= (N - idx)
        else:
            idx_a = bisect_left(a, k)
            idx_b = bisect_left(b, k)
            ans *= (N - idx_a) * (M - idx_b) - (N * M - k)
    return ans % (10**9 + 7)

N, M = [int(i) for i in input().split()]
A = [int(i) for i in input().split()]
B = [int(i) for i in input().split()]
print(d_double_landxcape(N, M, A, B))

Fixed submission:
def d_double_landxcape(N, M, A, B):
    """
    N行M列のグリッドに1からNMまでの整数を重複なく書き込む。このとき、以下の条件を満たす。
    ・i行目に書き込まれている値のうち、最大の値はA_i
    ・j行目に書き込まれている値のうち、最大の値はA_j
    書き込み方の総数を10**9+7で割った余りを求めよ。
    """

    # Aの各要素、またはBの各要素の中で、同じ値があるならば解は0
    # (異なる行/列に同じ数字を書き込むことは不可能)。
    # グリッドの中のxが書かれうる場所について、xが大きな順に考える。

    # 1. xがA_iとB_jの両方に現れる場合
    # xの場所は一意に定まる。

    # 2. xがA_iとB_jの片方に現れる場合
    # xがA_iに現れている場合、xの場所としてありうるものの個数は、
    # (B_j >= x となるjの個数) である。
    # xはA_i行にしか書き込めないし、B_j < x となる列に書き込むと
    # 矛盾してしまうため。

    # 3. xがAにもBにも現れない場合
    # xの場所としてありうるものの個数は、
    # (A_i >= x となるiの個数) * (B_j >= x となるjの個数) である。
    # ただし、そのうち NM - x 個はxより大きな値が書き込まれている。

    # 以上の値の総乗が解である。
    from bisect import bisect_left
    MOD = 10**9 + 7

    a = sorted(A)
    b = sorted(B)
    a_set = set(A)
    b_set = set(B)
    if len(a) != len(a_set) or len(b) != len(b_set):
        return 0  # 重複する要素があった。矛盾する。

    ans = 1
    for k in range(N * M, 0, -1):
        cond1 = k in a_set
        cond2 = k in b_set
        # 順に、上にコメントした、条件1. 2. 3. を満たす場合
        if cond1 and cond2:
            continue
        elif cond1:
            idx = bisect_left(b, k)
            ans *= (M - idx)
        elif cond2:
            idx = bisect_left(a, k)
            ans *= (N - idx)
        else:
            idx_a = bisect_left(a, k)
            idx_b = bisect_left(b, k)
            ans *= (N - idx_a) * (M - idx_b) - (N * M - k)
        ans %= MOD
    return ans % MOD

N, M = [int(i) for i in input().split()]
A = [int(i) for i in input().split()]
B = [int(i) for i in input().split()]
print(d_double_landxcape(N, M, A, B))