#include <bits/stdc++.h>
using namespace std;

using ll = long long;
using ld  = long double;
using pll = pair<ll, ll>;
using pld = pair<ld, ld>;
const int INF=1e9+7;
const ll LINF=9223372036854775807;
const ll MOD=1e9+7;
const ld PI=acos(-1);
const ld EPS = 1e-10; //微調整用（EPSより小さいと0と判定など）

int ii() { int x; if (scanf("%d", &x)==1) return x; else return 0; }
long long il() { long long x; if (scanf("%lld", &x)==1) return x; else return 0; }
string is() { string x; cin >> x; return x; }
char ic() { char x; cin >> x; return x; }
void oi(int x) { printf("%d ", x); }
void ol(long long x) { printf("%lld ", x); }
void od_nosp(double x) { printf("%.15f", x); } // 古い問題用
void od(double x) { printf("%.15f ", x); }
// long doubleで受け取り、fをLfなどに変えて出力すると、変な数値が出る
// それをなんとかするには独自の出力を作らなければならなそう
void os(const string &s) { printf("%s ", s.c_str()); }
void oc(const char &c) { printf("%c ", c); }
#define o_map(v){cerr << #v << endl; for(const auto& xxx: v){cout << xxx.first << " " << xxx.second << "\n";}} //動作未確認
void br() { putchar('\n'); }

// #define gcd __gcd //llは受け取らない C++17~のgcdと違うので注意
// int lcm(int a, int b){return a / gcd(a, b) * b;}
#define begin_end(a) a.begin(),a.end() //sort(begin_end(vec));
#define REP(i,m,n) for(ll i=(ll)(m) ; i < (ll)(n) ; i++ )
#define DREP(i,m,n) for(ll i=(ll)(m) ; i > (ll)(n) ; i-- )
#define rep(i,n) REP(i,0,n)
#define m_p(a,b) make_pair(a,b)
#define SORT_UNIQUE(c) (sort(c.begin(),c.end()), c.resize(distance(c.begin(),unique(c.begin(),c.end()))))
#define p_b push_back
#define SZ(x) ((ll)(x).size()) //size()がunsignedなのでエラー避けに
#define endk '\n'


// coutによるpairの出力（空白区切り）
template<typename T1, typename T2> ostream& operator<<(ostream& s, const pair<T1, T2>& p) {return s << "(" << p.first << " " << p.second << ")";}
// coutによるvectorの出力（空白区切り）
template<typename T> ostream& operator<<(ostream& s, const vector<T>& v) {
  int len = v.size();
  for (int i = 0; i < len; ++i) {
    s << v[i]; if (i < len - 1) s << " "; //"\t"に変えるとTabで見やすく区切る
  }
  return s;
}
// coutによる多次元vectorの出力（空白区切り）
template<typename T> ostream& operator<<(ostream& s, const vector< vector<T> >& vv) {
  int len = vv.size();
  for (int i = 0; i < len; ++i) {
    s << vv[i] << endl;
  }
  return s;
}

//最大値、最小値の更新。更新したor等しければtrueを返す
template<typename T>
bool chmax(T& a, T b){return (a = max(a, b)) == b;}
template<typename T>
bool chmin(T& a, T b){return (a = min(a, b)) == b;}

//4近傍（上下左右） rep(i, 2) にすると右・下だけに進む
vector<int> dx_4 = {1, 0, -1, 0};
vector<int> dy_4 = {0, 1, 0, -1};

// -------- template end - //


// - library ------------- //

// modint: mod 計算を int を扱うように扱える構造体
template<int MOD> struct Fp {
  long long val;
  constexpr Fp(long long v = 0) noexcept : val(v % MOD) {
    if (val < 0) val += MOD;
  }
  constexpr int getmod() { return MOD; }
  constexpr Fp operator - () const noexcept {
    return val ? MOD - val : 0;
  }
  constexpr Fp operator + (const Fp& r) const noexcept { return Fp(*this) += r; }
  constexpr Fp operator - (const Fp& r) const noexcept { return Fp(*this) -= r; }
  constexpr Fp operator * (const Fp& r) const noexcept { return Fp(*this) *= r; }
  constexpr Fp operator / (const Fp& r) const noexcept { return Fp(*this) /= r; }
  constexpr Fp& operator += (const Fp& r) noexcept {
    val += r.val;
    if (val >= MOD) val -= MOD;
    return *this;
  }
  constexpr Fp& operator -= (const Fp& r) noexcept {
    val -= r.val;
    if (val < 0) val += MOD;
    return *this;
  }
  constexpr Fp& operator *= (const Fp& r) noexcept {
    val = val * r.val % MOD;
    return *this;
  }
  constexpr Fp& operator /= (const Fp& r) noexcept {
    long long a = r.val, b = MOD, u = 1, v = 0;
    while (b) {
      long long t = a / b;
      a -= t * b; swap(a, b);
      u -= t * v; swap(u, v);
    }
    val = val * u % MOD;
    if (val < 0) val += MOD;
    return *this;
  }
  constexpr bool operator == (const Fp& r) const noexcept {
    return this->val == r.val;
  }
  constexpr bool operator != (const Fp& r) const noexcept {
    return this->val != r.val;
  }
  friend constexpr ostream& operator << (ostream &os, const Fp<MOD>& x) noexcept {
    return os << x.val;
  }
  friend constexpr Fp<MOD> modpow(const Fp<MOD> &a, long long n) noexcept {
    if (n == 0) return 1;
    auto t = modpow(a, n / 2);
    t = t * t;
    if (n & 1) t = t * a;
    return t;
  }
};

using mint = Fp<MOD>;

// エラトステネスの篩に基づく高速な素因数分解
// 前処理したあと O(logN)でNを素因数分解
// 以下のページのライブラリを改造したもの
// https://qiita.com/rsk0315_h4x/items/ff3b542a4468679fb409
class smart_sieve {
  ll L, R, M;
  std::vector<int> small;  // 小さい篩
  std::vector<std::vector<ll>> large;  // 大きい篩
  std::vector<ll> aux;  // aux[i] := large[i] の素因数の積

public:
  smart_sieve(ll L, ll R): L(L), R(R), M(sqrt(R)+1) {
    small.resize(M);
    std::iota(small.begin(), small.end(), 0);
    large.resize(R-L);
    aux.assign(R-L, 1);

    for (ll i = 2; i*i < R; ++i) {
      if (small[i] < i) continue;
      small[i] = i;
      for (ll j = i*i; j < M; j += i)
        if (small[j] == j) small[j] = i;

      for (ll j = (L+i-1)/i*i; j < R; j += i) {
        ll k = j;
        do {
          // aux[j-L] > M で判定した方がいいかも？
          // j / aux[j-L] < M の方がいい？（割り算したくない）
          if (aux[j-L] * aux[j-L] > R) break;

          large[j-L].push_back(i);
          aux[j-L] *= i;
          k /= i;
        } while (k % i == 0);
      }
    }
  }

  // 素因数分解 O(logN) 
  // factor(i) : i の素因数vector : f(120) = 2 2 2 3 5（ソート済）
  // 0 を渡すと おかしい答えが返ってくる。
  // 1 を渡すと {} を返す。
  std::vector<ll> prime_factorize(ll n) {
    assert(L <= n && n < R);
    std::vector<ll> res = large[n-L];
    n /= aux[n-L];
    if (n >= M) {
      // この場合，n は素数となることが示せる（はず）
      // n*n >= R だとオーバーフローしそう？
      res.push_back(n);
      return res;
    }
    while (n > 1) {
      res.push_back(small[n]);
      n /= small[n];
    }
    return res;
  }

  // 約数列挙ライブラリ（ llpow() を含めること！）
  // 非ソート約数列挙 O(logN)+O(dN) ※第二引数を渡さない場合
  // ソート約数列挙 O(logN)+O(dN)+O(dNlogdN) ※第二引数を true に
  // ※ dN = d(N) = σ0(N) = 自然数Nの約数の個数

  // ソート約数列挙をする際は約数の個数に注意
  // その範囲の高度合成数を見れば、約数の個数のmaxが大体分かる
  // （高度合成数一覧）http://wwwhomes.uni-bielefeld.de/achim/highly.txt
  // N<=10^9のとき、log(N)=約30, 約数の個数の最大は735,134,400の1,344個
  // --> ソート約数列挙 : 30+1344+1344*30= 41,694回
  // N<=10^8 のとき O(27)+O(768)+O(768*27)= 21,531回
  // N<=10^7のときd(N)最大は448, N<=10^6のときd(N)最大は240
  // 結論：ソート約数列挙はlong longの範囲内なら全部いけそうだが、1~Nについて行うのは10^5でギリギリか
  std::vector<ll> divisors(ll n, bool sorted = false) {
    assert(L <= n && n < R);
    std::vector<ll> pfactors = large[n-L];
    n /= aux[n-L];
    bool n_is_prime = false;
    if (n >= M) {
      // この場合，n は素数となることが示せる（はず）
      // n*n >= R だとオーバーフローしそう？
      pfactors.push_back(n);
      n_is_prime = true;
    }
    if (!n_is_prime){
      while (n > 1) {
        pfactors.push_back(small[n]);
        n /= small[n];
      }
    }

    map<ll, ll> map_pfactors;
    for (ll pfac : pfactors){
      map_pfactors[pfac]++;
    }

    // 約数列挙
    std::vector<ll> res;
    ll len = map_pfactors.size(); // 素因数の種類数
    // 再帰関数で約数を列挙
    make_divisors_from_pfacs(map_pfactors, res, 1, 0);

    // 第二引数が true だった場合、 res をソート
    if (sorted) sort(res.begin(), res.end());

    return res;
  }

  // <素因数, 個数> のmapを受け取り、vector resに約数を入れる再帰関数
  // depth := 今見るべき素因数が何個目か(0-indexed) -> map_pfactors[depth]
  void make_divisors_from_pfacs(map<ll, ll> &map_pfactors, vector<ll> &divs_vec, ll nowres, ll depth){
    auto itr = next(map_pfactors.begin(), depth);
    if (itr == map_pfactors.end()){
      // 全ての素因数を処理し終わったので、約数をvectorに入れて終了
      // 素因数が1つも無い場合（n=1の場合）、最初からこれになるので、1のみが約数として返される
      divs_vec.push_back(nowres);
      return;
    }
    ll nowpfac = (*itr).first;
    ll nowpfacnum = (*itr).second;
    ll multiplier = 1;
    rep(i, nowpfacnum+1){
      ll tmpres = nowres * multiplier;
      make_divisors_from_pfacs(map_pfactors, divs_vec, tmpres, depth+1);
      multiplier *= nowpfac;
    }
  }


};

// smart_sieve(L, R) で [L, R) を前計算
ll L = 1;
ll R = 1000001;
smart_sieve ss(L, R);

// --------- library end - //


int main(){

  ll N = il();
  vector<ll> as;
  rep(i, N){
    as.push_back(il());
  }

  // lcmsum_pfacs := a1~anの最小公倍数を求めるため、a1~anまでを素因数分解し、各素因数の指数をchmaxしていったものを格納するmap
  map<ll, ll> lcmsum_pfacs;

  // 各aiの素因数分解を格納する
  vector<vector<ll> > as_pfacs(N, vector<ll>() );

  // 素因数の指数をmapにして、lcmsum_pfacsのchmaxをしていく  
  rep(i, N){
    as_pfacs[i] = ss.prime_factorize(as[i]);

    map<ll, ll> pfac_cnt;
    for (ll ai_pfac : as_pfacs[i]){
      pfac_cnt[ai_pfac]++;
    }

    for (pll eachpfac : pfac_cnt){
      chmax(lcmsum_pfacs[eachpfac.first], eachpfac.second);
    }
  }

  // lcmsum を求める
  // lcmsum := a1~anの最小公倍数 mod P
  mint lcmsum = 1;
  for (pll eachpfac : lcmsum_pfacs){
    mint pfac = eachpfac.first;
    ll cnt = eachpfac.second;
    rep(i, cnt) lcmsum *= pfac;
  }

  // ここから先はmodintで処理する

  // 答えの計算
  // Σ(i:1~N)lcmsum/ai
  mint ans = 0;
  rep(i, N) ans += lcmsum / mint(as[i]);

  cout << ans << endk;
  
}

Measured memory_bytes: 79428