#ifndef LOCAL #pragma GCC optimize("O3") #endif #include using namespace std; #define sim template muu & operator<<( #define ris return *this #define R22(r) sim> typename enable_if<1 r sizeof(dud(0)),muu&>::type operator<<(c g) { sim> struct rge {c b, e;}; sim> rge range(c i, c j) {return rge{i, j};} sim> auto dud(c*r)->decltype(cerr << *r); sim> char dud(...); struct muu { #ifdef LOCAL stringstream a; ~muu() {cerr << a.str() << endl;} R22(<) a << boolalpha << g; ris;} R22(==) ris << range(begin(g), end(g));} sim mor rge u) { a << "["; for (c i = u.b; i != u.e; ++i) *this << ", " + 2 * (i == u.b) << *i; ris << "]"; } sim, class b mor pair r){ris << "(" << r.first << ", " << r.second << ")";} #else sim mor const c&){ris;} #endif }; #define debug muu() << __FUNCTION__ << "#" << __LINE__ << ": " #define imie(r...) "[" #r ": " << (r) << "] " #define range(a, b) "[[" #a ", " #b "): " << range(a, b) << "] " #define arr(a, i) "[" #a imie(i) ": " << a[i] << "] " using ll = long long; using ld = long double; using pii = pair ; const int mod = 1e9 + 7; int FastMin(int x, int y) {return x - y >> 31 & (x ^ y) ^ y;} int FastAbs(int x) {return (x ^ x >> 31) - (x >> 31);} #define ctz __builtin_ctz int gcd(int a, int b) { debug << imie(a) imie(b); int aa = ctz(a), bb = ctz(b); int r = FastMin(aa, bb); a >>= aa; b >>= bb; while (true) { int c = FastAbs(a - b); a = FastMin(a, b); b = c; if (b) b >>= ctz(b); else break; } return (a + b) << r; } #define log l0g #define tree tRee const int nax = 1 << 18, log = 18; pii tree[nax * 2]; pii read_max(int l, int r) { l += nax - 1; r += nax + 1; pii ans = {0, 0}; while (l / 2 != r / 2) { if (l % 2 == 0) ans = max(ans, tree[l + 1]); if (r % 2 == 1) ans = max(ans, tree[r - 1]); l /= 2; r /= 2; } return ans; } int gcdarr[nax][log]; int a[nax]; int read_gcd(int l, int r) { int len = (r - l + 1); int si = 31 - __builtin_clz(len); assert(len >= (1 << si) && len < (1 << (si + 1))); return gcd(gcdarr[l][si], gcdarr[r -(1 << si) + 1][si]); } ll ans = 0; void go(int l, int r) { if (l > r) return; int m = read_max(l, r).second; assert(m >= l && m <= r); vector left, right; int p = m; while (p >= l) { int tar = read_gcd(p, m); int low = l, high = p; while (low < high) { int med = (low + high) / 2; if (read_gcd(med, m) == tar) high = med; else low = med + 1; } left.emplace_back(tar, p - low + 1); p = low - 1; } debug << imie(left) range(a + l, a + m + 1); p = m; while (p <= r) { int tar = read_gcd(m, p); int low = p, high = r; while (low < high) { int med = (low + high + 1) / 2; if (read_gcd(m, med) == tar) low = med; else high = med - 1; } right.emplace_back(tar, low - p + 1); p = high + 1; } debug << imie(right) range(a + m, a + r + 1); ll inc = 0; for (int i = 0; i < (int) left.size(); ++i) { int g = left[i].first; for (int j = 0; j < (int) right.size(); ++j) { g = gcd(g, right[j].first); inc = (inc + g * right[j].second % mod * left[i].second) % mod; } } ans = (ans + inc * a[m]) % mod; go(l, m - 1); go(m + 1, r); } int main() { int n; scanf("%d", &n); for (int i = 0; i < n; ++i) { scanf("%d", a + i); tree[i + nax] = make_pair(a[i], i); gcdarr[i][0] = a[i]; } for (int i = nax - 1; i; --i) tree[i] = max(tree[i * 2], tree[i * 2 + 1]); for (int de = 0; de + 1 < log; ++de) for (int i = 0; i < n; ++i) { if (gcdarr[i + (1 << de)][de] == 0) break; gcdarr[i][de + 1] = gcd(gcdarr[i][de], gcdarr[i + (1 << de)][de]); } #ifdef LOCAL for (int i = 0; i < n; ++i) for (int j = i; j < n; ++j) { int br = a[i]; for (int k = i + 1; k <= j; ++k) br = gcd(br, a[k]); assert(br == read_gcd(i, j)); } ll out = 0; for (int i = 0; i < n; ++i) for (int j = i; j < n; ++j) { int m = read_max(i, j).first; int g = read_gcd(i, j); out = (out + m * g) % mod; } debug << imie(out); #endif go(0, n - 1); ans %= mod; if (ans < 0) ans += mod; printf("%lld\n", ans); }