#include <bits/stdc++.h>
using namespace std;
template <typename T>
T read() {
  T res;
  std::cin >> res;
  return res;
}
template <typename T>
void print(const T& t) {
  std::cout << t;
}
template <>
int read<int>() {
  int res;
  scanf("%d", &res);
  return res;
}
template <>
void print<int>(const int& t) {
  printf("%d", t);
};
template <>
unsigned int read<unsigned int>() {
  unsigned int res;
  scanf("%u", &res);
  return res;
}
template <>
void print<unsigned int>(const unsigned int& t) {
  printf("%u", t);
};
template <>
int64_t read<int64_t>() {
  int64_t res;
  scanf("%lld", &res);
  return res;
}
template <>
void print<int64_t>(const int64_t& t) {
  printf("%lld", t);
};
template <>
float read<float>() {
  float res;
  scanf("%f", &res);
  return res;
}
template <>
void print<float>(const float& t) {
  printf("%f", t);
};
template <>
double read<double>() {
  double res;
  scanf("%lf", &res);
  return res;
}
template <>
void print<double>(const double& t) {
  printf("%lf", t);
};
template <>
char read<char>() {
  char res;
  scanf("%c", &res);
  return res;
}
template <>
void print<char>(const char& t) {
  printf("%c", t);
};
namespace internal {
template <typename ValueT>
class IterableRange {
 public:
  class iterator {
   public:
    iterator(ValueT v__) : v_(v__) {}
    iterator& operator++() {
      ++v_;
      return *this;
    }
    bool operator==(iterator rhs) const { return v_ == rhs.v_; }
    bool operator!=(iterator rhs) const { return v_ != rhs.v_; }
    ValueT operator*() const { return v_; }
    ValueT operator->() const { return v_; }

   private:
    ValueT v_ = {};
  };
  IterableRange(ValueT begin__, ValueT end__)
      : begin_value_(std::min(begin__, end__)), end_value_(end__) {}
  iterator begin() const { return {begin_value_}; }
  iterator end() const { return {end_value_}; }

 private:
  ValueT begin_value_ = {};
  ValueT end_value_ = {};
};
}  // namespace internal
template <typename ValueT>
internal::IterableRange<ValueT> range(ValueT end) {
  return {{}, end};
}
template <typename ValueT>
internal::IterableRange<ValueT> range(ValueT begin, ValueT end) {
  return {begin, end};
}
template <typename T>
std::vector<T> readVector(size_t size) {
  std::vector<T> res(size);
  for (auto& elt : res) elt = read<T>();
  return res;
}
template <typename T>
int sgn(T val) {
  return (T(0) < val) - (val < T(0));
}
namespace {
inline uint64_t gcdInternal(uint64_t a, uint64_t b) {
  if (b == 0) return a;
  return gcdInternal(b, a % b);
}
inline uint64_t gcdDecompositionInternal(uint64_t a, uint64_t b, int64_t& x,
                                         int64_t& y) {
  if (b == 0) {
    x = 1;
    y = 0;
    return a;
  }
  int64_t xx, yy;
  auto gcd = gcdDecompositionInternal(b, a % b, xx, yy);
  x = yy;
  y = xx - (a / b) * yy;
  return gcd;
}
}  // namespace
inline uint64_t greatestCommonDivisor(int64_t a, int64_t b) {
  a *= sgn(a);
  b *= sgn(b);
  if (a < b) std::swap(a, b);
  return gcdInternal(a, b);
}
inline uint64_t greatestCommonDivisor(const std::vector<int64_t>& numbers) {
  uint64_t res = 0;
  for (auto a : numbers) res = greatestCommonDivisor(res, a);
  return res;
}
inline uint64_t gcdDecomposition(int64_t a, int64_t b, int64_t& x, int64_t& y) {
  auto aUnsigned = a * sgn(a);
  auto bUnsigned = b * sgn(b);
  auto gcd = (aUnsigned < bUnsigned)
                 ? gcdDecompositionInternal(aUnsigned, bUnsigned, x, y)
                 : gcdDecompositionInternal(bUnsigned, aUnsigned, y, x);
  x *= sgn(a);
  y *= sgn(b);
  return gcd;
}
template <typename UnderlyingInt, UnderlyingInt MOD>
class Residue {
 public:
  Residue(UnderlyingInt from = 0) {
    UnderlyingInt remainder = from % MOD;
    if (remainder < 0) remainder += MOD;
    rep_ = remainder;
  }
  bool operator==(Residue<UnderlyingInt, MOD> other) const {
    return rep_ == other.rep_;
  }
  Residue<UnderlyingInt, MOD> operator++(int) {
    return *this = Residue(rep_ + 1);
  }
  Residue<UnderlyingInt, MOD> operator++() { return *this = Residue(rep_ + 1); }
  Residue<UnderlyingInt, MOD> operator--(int) {
    return *this = Residue(rep_ - 1);
  }
  Residue<UnderlyingInt, MOD> operator--() { return *this = Residue(rep_ - 1); }
  Residue<UnderlyingInt, MOD> operator+=(Residue<UnderlyingInt, MOD> v) {
    return *this = Residue(rep_ + v.rep());
  }
  Residue<UnderlyingInt, MOD> operator-=(Residue<UnderlyingInt, MOD> v) {
    return *this = Residue(rep_ - v.rep());
  }
  Residue<UnderlyingInt, MOD> operator*=(Residue<UnderlyingInt, MOD> v) {
    return *this = Residue(rep_ * v.rep());
  }
  Residue<UnderlyingInt, MOD> inversed() const {
    int64_t x, y;
    auto gcd = gcdDecomposition(rep_, MOD, x, y);
    assert(gcd == 1);
    return {x};
  }
  UnderlyingInt rep() const { return rep_; }

 private:
  UnderlyingInt rep_;
};
template <typename UnderlyingInt, UnderlyingInt MOD>
Residue<UnderlyingInt, MOD> operator+(Residue<UnderlyingInt, MOD> a,
                                      Residue<UnderlyingInt, MOD> b) {
  return a += b;
}
template <typename UnderlyingInt, UnderlyingInt MOD>
Residue<UnderlyingInt, MOD> operator-(Residue<UnderlyingInt, MOD> a,
                                      Residue<UnderlyingInt, MOD> b) {
  return a -= b;
}
template <typename UnderlyingInt, UnderlyingInt MOD>
Residue<UnderlyingInt, MOD> operator*(Residue<UnderlyingInt, MOD> a,
                                      Residue<UnderlyingInt, MOD> b) {
  return a *= b;
}
template <typename UnderlyingInt, UnderlyingInt MOD>
Residue<UnderlyingInt, MOD> operator+(Residue<UnderlyingInt, MOD> a,
                                      UnderlyingInt b) {
  return a += b;
}
template <typename UnderlyingInt, UnderlyingInt MOD>
Residue<UnderlyingInt, MOD> operator-(Residue<UnderlyingInt, MOD> a,
                                      UnderlyingInt b) {
  return a -= b;
}
template <typename UnderlyingInt, UnderlyingInt MOD>
Residue<UnderlyingInt, MOD> operator*(Residue<UnderlyingInt, MOD> a,
                                      UnderlyingInt b) {
  return a *= b;
}
template <typename UnderlyingInt, UnderlyingInt MOD>
Residue<UnderlyingInt, MOD> operator/(Residue<UnderlyingInt, MOD> a,
                                      Residue<UnderlyingInt, MOD> b) {
  return a *= b.inversed();
}
template <typename UnderlyingInt, UnderlyingInt MOD>
Residue<UnderlyingInt, MOD> operator/(Residue<UnderlyingInt, MOD> a,
                                      UnderlyingInt b) {
  return a *= Residue<UnderlyingInt, MOD>(b).inversed();
}
template <typename UnderlyingInt, UnderlyingInt MOD>
std::ostream& operator<<(std::ostream& outStream,
                         Residue<UnderlyingInt, MOD> a) {
  return outStream << a.rep();
}
const int cCodeforcesModulo = 1000000007;
using CodeforcesResidue = Residue<int, cCodeforcesModulo>;
using CodeforcesResidue64 = Residue<int64_t, cCodeforcesModulo>;
template <typename T>
void relax_max(T& relaxWhat, const T& relaxBy) {
  relaxWhat = std::max(relaxWhat, relaxBy);
}
template <typename T>
void relax_min(T& relaxWhat, const T& relaxBy) {
  relaxWhat = std::min(relaxWhat, relaxBy);
}
using namespace std;
class Solver427C {
 public:
  void run();
  vector<vector<int>> g, gr;
  vector<char> used;
  vector<int> order, component;
  void dfs1(int v) {
    used[v] = true;
    for (size_t i = 0; i < g[v].size(); ++i)
      if (!used[g[v][i]]) dfs1(g[v][i]);
    order.push_back(v);
  }
  void dfs2(int v) {
    used[v] = true;
    component.push_back(v);
    for (size_t i = 0; i < gr[v].size(); ++i)
      if (!used[gr[v][i]]) dfs2(gr[v][i]);
  }
};
void Solver427C::run() {
  int n;
  cin >> n;
  auto prices = readVector<int64_t>(n);
  g.resize(n);
  gr.resize(n);
  int nEdges;
  cin >> nEdges;
  for (int i : range(nEdges)) {
    int a, b;
    cin >> a >> b;
    --a;
    --b;
    g[a].push_back(b);
    gr[b].push_back(a);
  }
  used.assign(n, false);
  for (int i = 0; i < n; ++i)
    if (!used[i]) dfs1(i);
  vector<vector<int>> comps;
  used.assign(n, false);
  for (int i = 0; i < n; ++i) {
    int v = order[n - 1 - i];
    if (!used[v]) {
      dfs2(v);
      comps.push_back(move(component));
      component.clear();
    }
  }
  int64_t totalPrice = 0;
  CodeforcesResidue64 cnt = 1;
  for (auto& comp : comps) {
    int64_t minPrice = numeric_limits<int64_t>::max();
    for (auto ind : comp) relax_min(minPrice, prices[ind]);
    totalPrice += minPrice;
    CodeforcesResidue64 cntPerComp = 0;
    for (auto ind : comp)
      if (prices[ind] == minPrice) cntPerComp += 1;
    cnt *= cntPerComp;
  }
  cout << totalPrice << " " << cnt;
}
int main() {
  Solver427C solver;
  solver.run();
}
