首先我们可以观察出从一个点开始的连续gcd最多只有log个, 因为gcd每次最少除2,
然后我们暴力莫队转移就好啦。
#include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ALL(x) (x).begin(), (x).end() #define fio ios::sync_with_stdio(false); cin.tie(0); using namespace std; const int N = 1e4 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 + 7; const double eps = 1e-8; const double PI = acos(-1); template<class T, class S> inline void add(T &a, S b) {a += b; if(a >= mod) a -= mod;} template<class T, class S> inline void sub(T &a, S b) {a -= b; if(a < 0) a += mod;} template<class T, class S> inline bool chkmax(T &a, S b) {return a < b ? a = b, true : false;} template<class T, class S> inline bool chkmin(T &a, S b) {return a > b ? a = b, true : false;} mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); const int B = 130; int Log[N]; struct ST { int dp[N][15]; int ty; void build(int n, int b[]) { for(int i = -(Log[0] = -1); i < N; i++) Log[i] = Log[i - 1] + ((i & (i - 1)) == 0); for(int i = 1; i <= n; i++) dp[i][0] = b[i]; for(int j = 1; j <= Log[n]; j++) for(int i = 1; i + (1 << j) - 1 <= n; i++) dp[i][j] = __gcd(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]); } inline int query(int x, int y) { if(x > y) return 0; int k = Log[y - x + 1]; return __gcd(dp[x][k], dp[y - (1 << k) + 1][k]); } } rmq; int n, q, a[N]; LL ans[N]; LL tmp[N]; vector<int> LP[N], RP[N]; vector<int> LV[N], RV[N]; struct Qus { int L, R, id; bool operator < (const Qus &rhs) const { if(L / B == rhs.L / B) return R < rhs.R; return L < rhs.L; } } qus[N]; void init() { for(int i = 1; i <= n; i++) { LP[i].clear(); RP[i].clear(); LV[i].clear(); RV[i].clear(); } } int main() { int T; scanf("%d", &T); while(T--) { scanf("%d", &n); init(); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); } rmq.build(n, a); for(int i = 1; i <= n; i++) { int p = i, low, high, mid, gcd, ret; while(p <= n) { ret = p; gcd = rmq.query(i, p); RP[i].push_back(p); RV[i].push_back(gcd); low = p, high = n; while(low <= high) { mid = low + high >> 1; if(rmq.query(i, mid) == gcd) ret = mid, low = mid + 1; else high = mid - 1; } p = ret + 1; } RP[i].push_back(n + 1); RV[i].push_back(0); } for(int i = 1; i <= n; i++) { int p = i, low, high, mid, gcd, ret; while(p >= 1) { ret = p; gcd = rmq.query(p, i); LP[i].push_back(p); LV[i].push_back(gcd); low = 1, high = p; while(low <= high) { mid = low + high >> 1; if(rmq.query(mid, i) == gcd) ret = mid, high = mid - 1; else low = mid + 1; } p = ret - 1; } LP[i].push_back(0); LV[i].push_back(0); } scanf("%d", &q); for(int i = 1; i <= q; i++) { scanf("%d%d", &qus[i].L, &qus[i].R); qus[i].id = i; } sort(qus + 1, qus + 1 + q); int l = 1, r = 0; LL now = 0; for(int i = 1; i <= q; i++) { int L = qus[i].L, R = qus[i].R, id = qus[i].id; while(r < R) { r++; for(int i = 0; i < SZ(LP[r]) - 1; i++) { if(LP[r][i + 1] >= l) { now += 1LL * LV[r][i] * (LP[r][i] - LP[r][i + 1]); } else { now += 1LL * LV[r][i] * (LP[r][i] - l + 1); break; } } } while(l > L) { l--; for(int i = 0; i < SZ(RP[l]) - 1; i++) { if(RP[l][i + 1] <= r) { now += 1LL * RV[l][i] * (RP[l][i + 1] - RP[l][i]); } else { now += 1LL * RV[l][i] * (r - RP[l][i] + 1); break; } } } while(r > R) { for(int i = 0; i < SZ(LP[r]) - 1; i++) { if(LP[r][i + 1] >= l) { now -= 1LL * LV[r][i] * (LP[r][i] - LP[r][i + 1]); } else { now -= 1LL * LV[r][i] * (LP[r][i] - l + 1); break; } } r--; } while(l < L) { for(int i = 0; i < SZ(RP[l]) - 1; i++) { if(RP[l][i + 1] <= r) { now -= 1LL * RV[l][i] * (RP[l][i + 1] - RP[l][i]); } else { now -= 1LL * RV[l][i] * (r - RP[l][i] + 1); break; } } l++; } ans[id] = now; } for(int i = 1; i <= q; i++) { printf("%lld ", ans[i]); } } return 0; } /* */