#include using namespace std; #define MOD 1000000007 #define NONE -1 #define INF 1023456789 template ostream& operator<<(ostream &out, vector cont) { for(auto it=cont.begin(); it != cont.end(); ++it) out << (it==cont.begin()?"":" ") << *it; return out; } typedef long long ll; typedef pair pii; int gcd (int a, int b) { if (a == b) { return a; } if (a == 0) { return b; } if (b == 0) { return a; } return gcd(a%b, b%a); } int addMod (int a, int b) { return (a+b) % MOD; } typedef int (*Binop)(int, int); struct Segtree { Binop op; int dfl; int n; vector V; Segtree (Binop op0, int dfl0, int m) : op(op0), dfl(dfl0) { n = 1; while (n < m) { n *= 2; } V.resize(2*n, dfl); } Segtree (Binop op0, int dfl0, vector& src) : Segtree(op0, dfl0, src.size()) { for (int i = 0; i < n; i++) { V[n+i] = src[i]; } for (int i = n-1; i >= 1; i--) { V[i] = op(V[2*i], V[2*i + 1]); } } int L, R; int _get (int v, int l, int r) { if (l >= L && r <= R) { return V[v]; } if (r <= L || l >= R) { return 0; } int s = (l+r) / 2; int lget = _get(2*v, l, s); int rget = _get(2*v + 1, s, r); return op(lget, rget); } int get (int l, int r) { L = l; R = r; return _get(1, 0, n); } }; struct GCDTree : Segtree { GCDTree (int n) : Segtree(gcd, 0, n) {} GCDTree (vector& src) : Segtree(gcd, 0, src) {} int findFirstNdiv (int d, int i) { int curr = n + i; while (curr != 1 && V[curr] % d == 0) { curr /= 2; } if (V[curr] % d == 0) { return n; } while (curr < n) { if (V[2*curr] % d != 0) { curr = 2*curr; } else { curr = 2*curr + 1; } } return curr - n; } }; struct LazySegtree { Binop op; int dfl; int n; vector V, lazy; LazySegtree (Binop op0, int dfl0, int m) : op(op0), dfl(dfl0) { n = 1; while (n < m) { n *= 2; } V.resize(2*n, dfl); lazy.resize(2*n, dfl); } LazySegtree (Binop op0, int dfl0, vector& src) : LazySegtree(op0, dfl0, src.size()) { for (int i = 0; i < n; i++) { V[n+i] = src[i]; } for (int i = n-1; i >= 1; i--) { V[i] = op(V[2*i], V[2*i + 1]); } } virtual void calcVal (int v, int l, int r) = 0; void propagate (int v, int l, int r) { if (lazy[v] != dfl) { lazy[2*v] = lazy[v]; lazy[2*v+1] = lazy[v]; lazy[v] = dfl; int s = (l+r) / 2; calcVal(2*v, l, s); calcVal(2*v+1, s, r); } } int L, R; int _get (int v, int l, int r) { if (l >= L && r <= R) { return V[v]; } if (r <= L || l >= R) { return 0; } propagate(v, l, r); int s = (l+r) / 2; int lget = _get(2*v, l, s); int rget = _get(2*v+1, s, r); return op(lget, rget); } int get (int l, int r) { L = l; R = r; return _get(1, 0, n); } virtual int segmentVal (int l, int r, int val) = 0; int newVal; void _set (int v, int l, int r) { if (l >= L && r <= R) { lazy[v] = newVal; V[v] = segmentVal(l, r, newVal); return; } if (r <= L || l >= R) { return; } propagate(v, l, r); int s = (l+r) / 2; _set(2*v, l, s); _set(2*v + 1, s, r); V[v] = op(V[2*v], V[2*v + 1]); } void set (int l, int r, int val) { L = l; R = r; newVal = val; _set(1, 0, n); } }; struct SumSegtree : LazySegtree { SumSegtree (int m) : LazySegtree(addMod, 0, m) {} SumSegtree (vector& src) : LazySegtree(addMod, 0, src) {} void calcVal (int v, int l, int r) { V[v] = ((ll)(r - l) * lazy[v]) % MOD; } int segmentVal (int l, int r, int val) { return ((ll)(r - l) * val) % MOD; } }; int myMin (int a, int b) { return min(a, b); } struct MinSegtree : LazySegtree { MinSegtree (int m) : LazySegtree(myMin, INF, m) {} MinSegtree (vector& src) : LazySegtree(myMin, INF, src) {} void calcVal (int v, int l, int r) { V[v] = lazy[v]; } int segmentVal (int l, int r, int val) { return val; } }; int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int n; cin >> n; vector V(n); vector > sortedV(n); for (int i = 0; i < n; i++) { int val; cin >> val; V[i] = val; sortedV[i] = make_pair(val, i); } sort(sortedV.begin(), sortedV.end()); // gcds GCDTree gtree(V); // for each element calculate the index of the next larger element vector nextLarger(n, NONE); MinSegtree temp(n); for (int i = n-1; i >= 0; i--) { int val = sortedV[i].first; int pos = sortedV[i].second; nextLarger[pos] = temp.get(val, val + 1); temp.set(0, pos, val); } // the current "state" ll res = 0; SumSegtree vals(V); int i = 0; while (i < n) { int val = sortedV[i].first; int pos = sortedV[i].second; int j = i; for (; j < n && val == sortedV[j].first; j++) { int pos2 = sortedV[j].second; int next = nextLarger[pos2]; vals.set(pos, next, val); } j = i; for (; j < n && val == sortedV[j].first; j++) { int currGcd = V[j]; int currPos = j; int nextHop = gtree.findFirstNdiv(currGcd, currPos); while (currPos < n) { res += (nextHop - currPos) * vals.get(currPos, nextHop); res %= MOD; currPos = nextHop; nextHop = gtree.findFirstNdiv(currGcd, currPos); } } i = j; } cout << res << "\n"; return 0; }