cf475 D. CGCDSSQ
题意:
给定数组,q次询问,每次询问 x,求 \(\gcd(a_l,\dots, a_r)=x\) 的 \(<l,r>\) 对的数量
思路:
只需要注意到当左端点固定时 gcd 递减且不同的 gcd 只有 log 个
法一:
预处理:固定左端点,每次找 gcd 相同的一段,一段一段地跳
区间 gcd 用 st 表搞
int erfen(int L, int g, int l, int r) {
while(l < r) { //在[l,r]中找gcd[L,R]>=g的最大R
int mid = l + r + 1 >> 1;
if(ask(L, mid) >= g) l = mid; else r = mid - 1;
}
return l;
}
void sol() {
cin >> n; for(int i = 1; i <= n; i++) cin >> a[i];
initST();
map<int, ll> ans;
for(int l = 1; l <= n; l++)
for(int g = 0, r1 = l, r2; r1 <= n; r1 = r2 + 1) //跳
g = __gcd(g, a[r1]),
r2 = erfen(l, g, r1, n), //gcd[l,r1]=gcd[l,r2]=g
ans[g] += r2-r1+1;
int q; cin >> q; while(q--) {
int x; cin >> x; cout << ans[x] << endl;
}
}
法二:超简单写法
以 \(a_i\) 结尾的区间的 gcd 要么是 \(a_i\)(区间长度为1),要么从前面以 \(a_{i-1}\) 结尾的区间的 gcd(记为 \(g'\))继承即 \(\gcd(g',a_i)\)
开 map 转移即可。map 记录以 \(a_i\) 结尾的所有区间的不同 gcd 的数量,不会超过 log
void sol() {
int n; cin >> n;
map<int, ll> ans, mp[2];
for(int i = 1; i <= n; i++) {
mp[i&1].clear();
int x; cin >> x;
mp[i&1][x]++;
for(auto &[g,c]: mp[(i-1)&1])
mp[i&1][__gcd(g, x)] += c;
for(auto &[g,c]: mp[i&1]) ans[g] += c;
}
int q; cin >> q; while(q--) {
int x; cin >> x; cout << ans[x] << endl;
}
}

浙公网安备 33010602011771号