#include #define st first #define nd second #define fi first #define se second #define pb push_back #define ps(v) cout << v << " " #define pln(v) cout << v << "\n" #define entr cout << "\n" using namespace std; typedef long long ll; typedef long double ld; typedef pair pll; const int MAX = 500005; const ll q = 1000000007; const ll Q = q * 1ll, QQ = 1ll * q * q; int Tree_max[MAX], Tree_gcd[MAX]; int gcd(int a, int b) { return (b == 0) ? a : gcd(b, a % b); } void update_gcd(int l, int r, int b, int e, int a) { if (e <= l || r <= b) { } else if (l <= b && e <= r) { Tree_gcd[b+e] = a; } else { int be = (b + e) / 2; update_gcd(l, r, b, be, a); update_gcd(l, r, be, e, a); Tree_gcd[b+e] = gcd(Tree_gcd[b+be], Tree_gcd[be+e]); } } void update_max(int l, int r, int b, int e, int a) { if (e <= l || r <= b) { } else if (l <= b && e <= r) { Tree_max[b+e] = a; } else { int be = (b + e) / 2; update_max(l, r, b, be, a); update_max(l, r, be, e, a); Tree_max[b+e] = max(Tree_max[b+be], Tree_max[be+e]); } } int query_gcd(int l, int r, int b, int e) { if (e <= l || r <= b) { return 0; } else if (l <= b && e <= r) { return Tree_gcd[b+e]; } else { int be = (b + e) / 2; return gcd(query_gcd(l, r, b, be), query_gcd(l, r, be, e)); } } int query_max(int l, int r, int b, int e) { if (e <= l || r <= b) { return 0; } else if (l <= b && e <= r) { return Tree_max[b+e]; } else { int be = (b + e) / 2; return max(query_max(l, r, b, be), query_max(l, r, be, e)); } } inline int bin_search_j_right(int i, int l, int r, int &n, int d, int s2) { int m; while (l != r) { m = (l + r + 1) / 2; if (query_gcd(i, m+1, 0, s2) >= d) { l = m; } else { r = m-1; } } return l; } inline int bin_search_j_left(int i, int l, int r, int &n, int d, int s2) { int m; while (l != r) { m = (l + r) / 2; if (query_gcd(m, i+1, 0, s2) >= d) { r = m; } else { l = m+1; } } return l; } void solve() { int n; cin >> n; vector A(n); int s = 1, s2; while (s <= 2*n) { s *= 2; } s2 = s / 2; for (int i = 0; i < s; i++) { Tree_gcd[i] = Tree_max[i] = 0; } for (int i = 0; i < n; i++) { cin >> A[i]; update_gcd(i, i+1, 0, s2, A[i]); //update_max(i, i+1, 0, s2, A[i]); } vector Prev(n), Next(n); for (int i = 0; i < n; i++) { int j = i-1; while (j >= 0 && A[j] < A[i]) { j = Prev[j]; } Prev[i] = j; } for (int i = n-1; i >= 0; i--) { int j = i+1; while (j < n && A[j] < A[i]) { j = Next[j]; } Next[i] = j; } ll ans = 0; for (int p = 0; p < n; p++) { int a = A[p], i = Prev[p]+1, j = Next[p]-1; ll a0 = a; /* vector D; for (int i = 1; i*i <= a; i++) { if (a % i == 0) { D.push_back(i); if (a/i != i) { D.push_back(a/i); } } } sort(D.begin(), D.end()); reverse(D.begin(), D.end()); */ set S; { int d = A[p], l = p, r = p; while (d >= 1 && i <= l) { //cout << "Enter first p=" << p << " a=" << a << " | d=" << d << " l=" << l << " r=" << r << " i=" << i << " j=" << j <= Q) { cur %= q; } cur *= (l - i0 + 1); if (cur >= Q) { cur %= q; } cur *= (j0 - p + 1); if (cur >= Q) { cur %= q; } ans += cur; if (ans >= QQ) { ans %= q; } int d0 = d, j1 = j0+1, j2; while (j1 <= j) { d0 = gcd(d0, A[j1]); j2 = bin_search_j_right(i0, j1, j, n, d0, s2); cur = a0 * d0; if (cur >= Q) { cur %= q; } cur *= (l - i0 + 1); if (cur >= Q) { cur %= q; } cur *= (j2 - j1 + 1); if (cur >= Q) { cur %= q; } ans += cur; if (ans >= QQ) { ans %= q; } j1 = j2 + 1; if (j1 <= j) { d0 = gcd(d0, A[j1]); } } //cout << " i0=" << i0 << " j0=" << j0 << " ans=" << ans <= 1 && r <= j) { cout << "Enter second p=" << p << " a=" << a << " | d=" << d << " l=" << l << " r=" << r << " i=" << i << " j=" << j <= Q) { cur %= q; } cur *= (j0 - r + 1); if (cur >= Q) { cur %= q; } cur *= (p - i0 + 1); if (cur >= Q) { cur %= q; } ans += cur; if (ans >= QQ) { ans %= q; } S.insert(d); } cout << " i0=" << i0 << " j0=" << j0 << " ans=" << ans <