#include "bits/stdc++.h"
#define REP(i, n) for(int i = 0; i < int(n); i++)
#define FOR(i,n,m) for(int i = int(n); i < int(m); i++)
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;
const int INF = 1e9 + 6;
const ll LLINF = 1e18 + 1;

template<int mod>
struct mint {
private:
    long long x;
public:
    mint(long long x = 0) :x(x%mod) {}
    mint(std::string s) {
        long long z = 0;
        REP(i, s.size()) {
            z *= 10;
            z += s[i] - '0';
            z %= mod;
        }
        this->x = z;
    }
    mint& operator+=(const mint a) {
        if ((x += a.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator-=(const mint a) {
        if ((x += mod - a.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator*=(const mint a) {
        (x *= a.x) %= mod;
        return *this;
    }
    mint operator+(const mint a) const {
        mint res(*this);
        return res += a;
    }
    mint operator-(const mint a) const {
        mint res(*this);
        return res -= a;
    }
    mint operator*(const mint a) const {
        mint res(*this);
        return res *= a;
    }
    friend std::ostream& operator<<(std::ostream& os, const mint& n) {
        return os << n.x;
    }
    bool operator==(const mint a) const {
        return this->x == a.x;
    }
};

// 0-indexedとして使う
// 実装は1-indexed
template< typename T >
struct BinaryIndexedTree {
    std::vector< T > data;

    BinaryIndexedTree(int sz) {
        data.assign(++sz, 0);
    }

    // [0,k]
    inline T sum(int k) {
        T ret = 0;
        for (++k; k > 0; k -= k & -k) ret += data[k];
        return (ret);
    }

    // [left,right]
    inline T sum(int left, int right) {
        return sum(right) - sum(left - 1);
    }

    // k番目にxを加算
    // 負の数も可
    inline void add(int k, T x) {
        for (++k; k < data.size(); k += k & -k) data[k] += x;
    }

    // k番目の値 0-indexed
    // 値 = index, 個数 = data[index]
    // 0がdata[0]個, 1がdata[1]個...
    int get(ll k) {
        ++k;
        int res = 0;
        int N = 1; while (N < (int)data.size()) N *= 2;
        for (int i = N / 2; i > 0; i /= 2) {
            if (res + i < (int)data.size() && data[res + i] < k) {
                k = k - data[res + i];
                res = res + i;
            }
        }
        return res + 1;
    }

    void print() {
        std::cout << "[ ";
        for (int i = 0; i < data.size() - 1; i++) {
            std::cout << sum(i, i);
            if (i < data.size() - 2) cout << ", ";
        }
        std::cout << " ]" << endl;
    }
};

int main() {
    int n, m; cin >> n >> m;
    vector<bool> used1(n*m + 1, false);
    vector<bool> used2(n*m + 1, false);
    vector<int> a(n), b(m);
    REP(i, n) {
        cin >> a[i];
        if (used1[a[i]]) {
            puts("0");
            return 0;
        }
        used1[a[i]] = true;
    }
    REP(i,m) {
        cin >> b[i];
        if (used2[b[i]]) {
            puts("0");
            return 0;
        }
        used2[b[i]] = true;
    }
    BinaryIndexedTree<int> bit(n*m + 1);
    mint<MOD> ans = 1;
    REP(i, n) {
        REP(j, m) {
            bit.add(min(a[i], b[j]),1);
        }
    }
    int num = n * m ;
    for (int i = num; i >= 1; i--) {
        // タテヨコにある -> 場所が一意に決まる
        if (used1[i] && used2[i]) {
        }
        // タテかヨコのどちらかにある -> その列にしか入らない
        else if (used1[i] || used2[i]) {
            ans *= bit.sum(i,i);
        }
        else {
            ans *= bit.sum(i, n*m);
        }
        bit.add(i, -1);
    }
    cout << ans << endl;
    return 0;
}

Measured memory_bytes: 4352