D. CGCDSSQ (gcd&ST表)

考虑前缀 g c d gcd gcd 是非递增的,若不同最少 / 2 /2 /2 ,所以增加的 g c d gcd gcd 的个数 l o g log log

所以考虑用 m a p map map 维护前缀进行递推。

#include <bits/stdc++.h>
using namespace std;
 
int n, q;
map<int,long long> tmp, d, res;
int main() {
	scanf("%d",&n);
	for(int i = 0, x; i < n; i++) {
		scanf("%d",&x);
		tmp.clear();
		for(auto p: d) tmp[__gcd(x, p.first)] += p.second;
		tmp[x]++;
		swap(tmp, d);
		for(auto p: d) res[p.first] += p.second;
	}
	scanf("%d",&q);
	int x;
	while(q--) scanf("%d", &x), printf("%lld\n", res[x]);
}

此外还可以根据 g c d gcd gcd的非递增性,对每个左端点进行二分,按 g c d gcd gcd相同的一段进行二分,这样变化最多 l o g log log次,然后用个map统计答案即可。

下面的参考代码二分是的最小的第一个不同的gcd位置。

#include <bits/stdc++.h> 
using namespace std; 
#define maxn 101000
typedef long long LL; 

template <typename T> 
inline void read(T &s) {
	s = 0; 
	T w = 1, ch = getchar(); 
	while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
	while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
	s *= w; 
}

int n, m; 
int a[maxn], lg[maxn], q[maxn]; 
int f[maxn][25]; 
map <int, LL> ans; 

inline int gcd(int x, int y) { return y ? gcd(y, x % y) : x; } 

inline void pre_work() { // 预处理gcd
	lg[0] = -1; 
	for (int i = 1; i <= n; ++i) {
		lg[i] = lg[i >> 1] + 1, f[i][0] = a[i]; 
	}
	for (int j = 1; j <= 20; ++j) {
		for (int i = 1; i <= n - (1 << (j - 1)) + 1; ++i) {
			f[i][j] = gcd(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]); 
		}
	}
}

inline int query(int l, int r) { // 查询
	int t = lg[r - l + 1]; 
	return gcd(f[l][t], f[r - (1 << t) + 1][t]); 
}

void solve(int x) { // x 为固定的左端点
	int L = x, R = x; 
	while (R <= n) {
		int left = L, right = n; 
		int g = query(x, L); 
		while (left <= right) {
			int mid = (left + right) >> 1; 
			if (query(x, mid) == g) left = mid + 1; 
			else right = mid - 1; 
		}
		R = left; 
		ans[g] += (LL)R - L; 
		L = R; 
	}
} 

int main() {
	read(n); 
	for (int i = 1; i <= n; ++i) read(a[i]); 
	
	pre_work(); 
	
	for (int i = 1; i <= n; ++i) solve(i); // 处理左端点

	read(m); 
	for (int i = 1; i <= m; ++i) {
		int x; read(x); 
		printf("%lld\n", ans[x]); 
	}
	return 0; 
}