#include <bits/stdc++.h>
using namespace std;
using lint = long long int;
using pint = pair<int, int>;
class Void {
 public:
  template <typename T>
  Void& operator<<(const T&) {
    return *this;
  }
};
template <typename T>
T& getv(vector<T>& v, int i) {
  assert(i >= 0 && i < v.size());
  return v[i];
}
template <typename T>
const T& cgetv(const vector<T>& v, int i) {
  assert(i >= 0 && i < v.size());
  return v[i];
}
constexpr lint MOD = 1000000007;
constexpr int MAXSWEET = 5000;
constexpr int MAXLEN = 5000;
pair<int, lint> brute(const vector<int> sweet, const vector<pint> cowinput) {
  int n = sweet.size(), m = cowinput.size();
  int best = 0;
  lint numbest = 0;
  for (unsigned long long int mask = 0; mask < (1ULL << m); mask++)
    for (unsigned long long int mask2 = 0; mask2 < (1ULL << m); mask2++) {
      bool possible = true;
      vector<pint> left, right;
      for (int i = 0; i < m; i++) {
        if (mask & (1ULL << i)) {
          if (mask2 & (1ULL << i)) {
            left.push_back(cowinput[i]);
          } else {
            right.push_back(cowinput[i]);
          }
        } else if (mask2 & (1ULL << i)) {
          possible = false;
          break;
        }
      }
      if (!possible) continue;
      for (int i = 0; i < left.size(); i++)
        for (int j = 0; j < left.size(); j++)
          if (i != j && left[i].first == left[j].first) possible = false;
      for (int i = 0; i < right.size(); i++)
        for (int j = 0; j < right.size(); j++)
          if (i != j && right[i].first == right[j].first) possible = false;
      if (!possible) continue;
      int split = -1;
      for (pint c : left) {
        int s = c.first, h = c.second;
        for (int i = 0; i < n; i++) {
          split = max(split, i);
          if (sweet[i] == s) h--;
          if (h == 0) break;
        }
        if (h > 0) {
          possible = false;
          break;
        }
      }
      if (!possible) continue;
      for (pint c : right) {
        int s = c.first, h = c.second;
        for (int i = n - 1; i > split; i--) {
          if (sweet[i] == s) h--;
          if (h == 0) break;
        }
        if (h > 0) {
          possible = false;
          break;
        }
      }
      if (!possible) continue;
      int curr = left.size() + right.size();
      Void() << "Achieved " << curr << "\n";
      for (auto c : left) Void() << c.first << "," << c.second << "  ";
      Void() << "\n";
      for (auto c : right) Void() << c.first << "," << c.second << "  ";
      Void() << "\n";
      if (curr > best) {
        best = curr;
        numbest = 0;
      }
      if (curr == best) {
        numbest += 1;
      }
    }
  numbest %= MOD;
  return {best, numbest};
}
lint fastdiv(lint a, lint b) {
  lint bb = b;
  lint e = MOD - 2;
  while (e) {
    if (e & 1) a = a * bb % MOD;
    bb = bb * bb % MOD;
    e /= 2;
  }
  return a;
}
struct Sweet {
  int s;
  vector<int> cows;
  int lh = 0, rh = 0;
  int li = -1, ri = -1;
  int best = 0;
  lint count = 1;
};
pair<int, lint> solve(const vector<int> sweet, const vector<pint> cowinput) {
  int n = sweet.size();
  vector<Sweet> aux(n + 1);
  for (auto c : cowinput) {
    auto& s = aux[c.first];
    s.cows.push_back(c.second);
  }
  for (int s : sweet) {
    aux[s].rh += 1;
    aux[s].s = s;
  }
  int best = 0;
  lint numbest = 1;
  for (auto& s : aux) {
    sort(s.cows.begin(), s.cows.end());
    while (s.ri + 1 < s.cows.size() && s.cows[s.ri + 1] <= s.rh) s.ri += 1;
    s.best = (s.ri >= 0 ? 1 : 0);
    if (s.best == 1) {
      s.count = s.ri + 1;
      best += 1;
      numbest *= s.count;
      numbest %= MOD;
    } else {
      s.count = 1;
    }
    Void() << "  At split -1 and s = " << s.s << ": " << s.best << " "
           << s.count << "\n";
  }
  Void() << "After split -1: " << best << " " << numbest << "\n";
  int currbest = best;
  lint currnumbest = numbest;
  for (int split = 0; split < n; split++) {
    auto& s = aux[sweet[split]];
    s.lh += 1;
    s.rh -= 1;
    while (s.li + 1 < s.cows.size() && s.cows[s.li + 1] <= s.lh) s.li += 1;
    while (s.ri >= 0 && s.cows[s.ri] > s.rh) s.ri -= 1;
    int newbest;
    lint newcount;
    int maxc = max(s.ri, s.li) + 1;
    int minc = min(s.ri, s.li) + 1;
    if (maxc >= 2 && minc >= 1) {
      newbest = 2;
      newcount = maxc * minc - minc;
      assert(newcount >= 1);
    } else if (maxc >= 1) {
      newbest = 1;
      newcount = 2 * minc + (maxc - minc);
    } else {
      newbest = 0;
      newcount = 1;
    }
    currbest = currbest - s.best + newbest;
    currnumbest = fastdiv(currnumbest, s.count) * newcount % MOD;
    s.best = newbest;
    s.count = newcount;
    Void() << "At split " << split << " values for s=" << s.s << ": " << s.best
           << " " << s.count << "\n";
    Void() << "Current bests: " << best << " " << numbest << " " << currbest
           << " " << currnumbest << "\n";
    if (s.li >= 0 && s.cows[s.li] == s.lh) {
      Void() << "Can do split on " << split << "\n";
      lint fixedcount = s.count;
      if (s.best == 1) {
        fixedcount = 1;
      } else if (s.best == 2) {
        fixedcount = s.ri + 1 - (s.li <= s.ri ? 1 : 0);
      }
      Void() << "  (fixed count: " << fixedcount << ")\n";
      fixedcount = fastdiv(currnumbest, s.count) * fixedcount % MOD;
      if (currbest > best) {
        best = currbest;
        numbest = 0;
      }
      if (currbest == best) {
        numbest = (numbest + fixedcount) % MOD;
      }
      Void() << "Updated bests: " << best << " " << numbest << "\n";
    }
  }
  return {best, numbest};
}
void test() {
  srand(0);
  int t = 1000;
  while (t--) {
    int n = 6;
    int m = 5;
    int s = rand() % 3 + 1;
    vector<int> sweet(n);
    for (int i = 0; i < n; i++) sweet[i] = rand() % s + 1;
    vector<pint> cows(m);
    vector<set<int>> sset(s + 1);
    for (int i = 0; i < m; i++) {
      cows[i].first = rand() % s + 1;
      while (true) {
        int h = rand() % n + 1;
        if (sset[cows[i].first].count(h)) continue;
        cows[i].second = h;
        sset[cows[i].first].insert(h);
        break;
      }
    }
    Void() << "=======================\n";
    auto opt = solve(sweet, cows);
    auto bru = brute(sweet, cows);
    if (opt != bru) {
      Void() << "Wrong: " << opt.first << " " << opt.second << " vs "
             << bru.first << " " << bru.second << "\n";
      Void() << "Sweet: ";
      for (auto x : sweet) Void() << x << " ";
      Void() << "\n";
      Void() << "Cows: ";
      for (auto x : cows) Void() << x.first << "," << x.second << " ";
      Void() << "\n";
      break;
    }
  }
}
int main() {
  int n, m;
  cin >> n >> m;
  vector<int> sweet(n);
  for (int i = 0; i < n; i++) {
    cin >> sweet[i];
  }
  vector<pint> cowinput(m);
  for (int i = 0; i < m; i++) {
    int s, h;
    cin >> s >> h;
    cowinput[i] = pint(s, h);
  }
  auto res = solve(sweet, cowinput);
  cout << res.first << " " << res.second << "\n";
  return 0;
}
