#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <map>
#include <memory>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <sstream>
#include <unordered_map>
#include <vector>


#define INF 4000000000000000000LL
#define MOD 1000000007
#define ALL(x) std::begin(x), std::end(x)


class modint_t;


modint_t modpow(modint_t x, long long y);


class modint_t {
  friend std::ostream& operator<<(std::ostream& ofs, const modint_t a);

public:
  modint_t(long long xx = 0) : x(xx % MOD) {};

public:
  long long get() {
    normalize();

    return x;
  };

public:
  bool operator==(modint_t a) const {
    return x == a.x;
  };

  bool operator!=(modint_t a) const {
    return ! (*this == a);
  };

public:
  modint_t operator+(const modint_t& a) const {
    return (x + a.x) % MOD;
  };

  modint_t operator-(const modint_t& a) const {
    return (x - a.x) % MOD;
  };

  modint_t operator*(const modint_t& a) const {
    return x * a.x % MOD;
  };

  modint_t operator/(const modint_t& a) const {
    return (*this) * a.inversed();
  };

  // Note that operator^'s priority is quite low in C++...
  modint_t operator^(long long i) const {
    return modpow(x, i);
  };

public:
  modint_t& operator+=(const modint_t& a) {
    (x += a.x) %= MOD;

    return *this;
  };

  modint_t& operator-=(const modint_t& a) {
    (x -= a.x) %= MOD;

    return *this;
  };

  modint_t& operator*=(const modint_t& a) {
    (x *= a.x) %= MOD;

    return *this;
  };

  modint_t& operator/=(const modint_t& a) {	// Not tested
    (x *= a.inversed().x) %= MOD;

    return *this;
  };

public:
  modint_t inversed() const {
    assert(x % MOD);

    return modpow(x, MOD - 2);
  };

  void inverse() {
    assert(x % MOD);

    x = modpow(x, MOD - 2).x;
  };

private:
  void normalize() {
    while (! (0 <= x && x < MOD))
      x = (x + MOD) % MOD;
  };

private:
  long long x;
};

modint_t operator+(long long a, const modint_t& b)
{
  return modint_t(a) + b;
}

modint_t operator-(long long a, const modint_t& b)
{
  return modint_t(a) - b;
}

modint_t operator*(long long a, const modint_t& b)
{
  return modint_t(a) * b;
}

modint_t operator/(long long a, const modint_t& b)
{
  return modint_t(a) / b;
}

std::ostream& operator<<(std::ostream& ofs, modint_t a)
{
  a.normalize();

  ofs << a.x;

  return ofs;
}

modint_t modpow(modint_t x, long long y)
{
  modint_t xx = x, p = 1;

  for ( ; y; xx *= xx, y >>= 1)
    if (y & 1)
      p *= xx;

  return p;
}

modint_t modncr(int n, int r)
{
  assert(n >= 0);
  assert(r >= 0);

  if (n == 0)
    return r == 0 ? 1 : 0;

  if (r > n)
    return 0;

  modint_t num = 1, denom = 1;

  int dm = std::min(r, n - r);
  int dp = std::max(r, n - r);

  for (int i = dp + 1; i <= n; i ++)
    num *= i;

  for (int i = 2; i <= dm; i ++)
    denom *= i;

  return modpow(denom, MOD - 2) * num;
}

template<size_t T>
class modinv_t {
public:
  modinv_t() {
    modint_t x = a_[0] = 1;

    for (int i = 1; i < T; i ++)
      a_[i] = (x *= i).get();

    modint_t inv = modpow(a_[T - 1], MOD - 2);

    for (int i = T - 1; i > 0; inv *= i, i --)
      a_[i] = (a_[i - 1] * inv).get();

#if 0
    for (int i = 1; i < T; i ++)
      assert(i * a_[i] % MOD == 1);
#endif
  };

public:
  modint_t operator[](size_t i) const {
    assert(i < T);

    return a_[i];
  };

private:
  long long a_[T];
};

// modinv_t<T> modinv;	// T = 222,222


void check_if_possible(int* p, int n)
{
  std::set<int> set;

  for (int i = 0; i < n; i ++)
    set.insert(p[i]);

  if (set.size() == n)
    return;
  
  std::cout << 0 << std::endl;

  exit(0);
}


int main(int argc, char** argv)
{
  std::cin.tie(0);
  std::ios_base::sync_with_stdio(0);

  std::cout << std::fixed << std::setprecision(6);
  std::cerr << std::fixed << std::setprecision(6);

  int N, M, A[1111], B[1111], AA[1111], BB[1111];

  std::cin >> N >> M;

  std::set<int> set_a, set_b;

  for (int i = 0; i < N; i ++) {
    std::cin >> A[i];
    
    set_a.insert(A[i]);
  }

  for (int i = 0; i < M; i ++) {
    std::cin >> B[i];

    set_b.insert(B[i]);
  }

  if (set_a.size() != N || set_b.size() != M) {
    std::cout << 0 << std::endl;

    return 0;
  }

  memcpy(AA, A, sizeof(A));
  memcpy(BB, B, sizeof(B));

  std::sort(AA, AA + N);
  std::sort(BB, BB + M);

  modint_t C(1);

  int d = 0, e = 0;

  for (int n = N * M; n >= 1; n --) {
    bool has_a = std::binary_search(AA, AA + N, n);
    bool has_b = std::binary_search(BB, BB + M, n);
    
    if (has_a && has_b) {
      e ++;
    }
    else if (has_a) {
      int c = M - (std::lower_bound(BB, BB + M, n) - BB);

      C *= c;

      d ++;
    }
    else if (has_b) {
      int c = N - (std::lower_bound(AA, AA + N, n) - AA);
      
      C *= c;

      d ++;
    }
    else {
      int c =
        (N - (std::lower_bound(AA, AA + N, n) - AA)) *
        (M - (std::lower_bound(BB, BB + M, n) - BB)) - e;

      C *= c - d;

      d ++;
    }
  }

  std::cout << C << std::endl;

  return 0;
}


Measured memory_bytes: 384