# ARC023-D GCD区間 (解説AC)
試験管2511diff
https://atcoder.jp/contests/arc023/tasks/arc023_4
## 解法
gcdが減るときは、$\frac{1}{2}$以下になるので、減少する回数はたかだか$\log_{2}10^9$回 -> 同じ区間をまとめて計算する
## 実装
```cpp=
#include <bits/stdc++.h>
struct SparseTable {
std::vector<int> L;
std::vector<std::vector<int>> dat;
SparseTable(std::vector<int> A) : L(A.size() + 1), dat() {
for (int i{1} ; i < (int)L.size() ; i++) {
L[i] = L[i - 1] + (i >> (L[i - 1] + 1));
}
dat.resize(L.back() + 1);
dat[0] = A;
for (int i{1}, len{2} ; i < (int)dat.size() ; i++, len <<= 1) {
dat[i] = dat[i - 1];
for (int j{} ; j + len - 1 < (int)dat[i].size() ; j++) {
dat[i][j] = std::gcd(dat[i - 1][j], dat[i - 1][j + (len >> 1)]);
}
}
}
int product(int l, int r) const {
assert(0 <= l and l <= r and r <= (int)dat[0].size());
int now{L[r - l]};
return (l == r ? 0 : std::gcd(dat[now][l], dat[now][r - (1 << now)]));
}
};
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
int N, M;
std::cin >> N >> M;
std::vector<int> A(N);
for (auto& a : A) std::cin >> a;
SparseTable spt{A};
std::vector<std::pair<int, int>> kiyo;
std::vector<int> app;
kiyo.reserve(30 * N);
app.reserve(30 * N);
for (int i{} ; i < N ; i++) {
// std::cout << "start " << i + 1 << std::endl;
for (int j{i}, cur{A[i]} ; j < N ; ) {
if (cur == 1) {
kiyo.push_back(std::pair{ cur, N - j });
app.push_back(cur);
// map[cur] += N - j;
break;
}
else {
int ok{j + 1}, ng{N + 1};
while (ng - ok > 1) {
int mid{(ok + ng) / 2};
if (cur == spt.product(i, mid)) {
ok = mid;
}
else {
ng = mid;
}
}
kiyo.push_back(std::pair{ cur, ok - j });
app.push_back(cur);
j = ok;
cur = spt.product(i, std::min(N, j + 1));
}
// else {
// kiyo.push_back(std::pair{ cur, next[j] - j });
// app.push_back(cur);
// // map[cur] += next[j] - j;
// cur = spt.product(i, std::min(N, next[j] + 1));
// }
}
}
std::sort(app.begin(), app.end());
app.erase(std::unique(app.begin(), app.end()), app.end());
std::vector<long long> sum(app.size());
for (auto [g, num] : kiyo) {
sum[std::lower_bound(app.begin(), app.end(), g) - app.begin()] += num;
}
while (M--) {
int x;
std::cin >> x;
auto it{std::lower_bound(app.begin(), app.end(), x)};
std::cout << (it == app.end() or app[it - app.begin()] != x ? 0LL : sum[it - app.begin()]) << '\n';
}
}
```
[提出](https://atcoder.jp/contests/arc023/submissions/58600344)
## 感想
CF-Div3のボスでこういう考察をしたことがあったが、今回は引き出せなかった。残念。
ICPCではデータ構造系の問題を担当をしているため、クエリ問題はガンガン解説開いてインプットしていこうと思う。
- 数え上げも担当しているんだけど、今の所数え上げはいい感じに自力で解けてて嬉しい