题解:CF2094H La Vaca Saturno Saturnita
biyi_mouse · · 题解
根号分治题,可惜我没做出来(其实主要还是没想到第二种预处理)。
对于一个询问显然直接循环做没有前途,原因是会遍历很多 useless 状态无法改变 useful 状态跳到另一个 useful 状态。
首先会发现
这样做是
然后对于询问,按照最开始提到的思路做即可。需要注意的是我们每次需要在
const int N = 100010, B = 250;
int n, q, a[N];
int ne[N][B];
vector<int> divs[N], pos[N];
void solve() {
n = read(), q = read();
for (int i = 1; i <= n; i ++) a[i] = read();
for (int i = 1; i <= B; i ++) ne[n + 1][i] = n + 1;
for (int i = 1; i <= n; i ++) {
if (a[i] > B)
for (int j = a[i]; j <= N - 10; j += a[i])
pos[j].push_back(i);
}
for (int i = n; i >= 1; i --) {
for (int j = 1; j <= B; j ++) ne[i][j] = ne[i + 1][j];
if (a[i] <= B) ne[i][a[i]] = i;
}
while (q --) {
int k = read(), l = read(), r = read();
LL ans = 0;
for (int p = l; ; ) {
int R = r + 1;
for (auto x : divs[k])
if (x <= B) R = min(R, ne[p][x]);
auto it = lower_bound(pos[k].begin(), pos[k].end(), p);
if (it != pos[k].end()) R = min(R, *it);
ans += 1ll * (R - p) * k;
p = R;
if (p > r) break;
while (k % a[p] == 0) k /= a[p];
}
printf("%lld\n", ans);
}
for (int i = 1; i <= n; i ++) {
if (a[i] > B)
for (int j = a[i]; j <= N - 10; j += a[i])
pos[j].clear();
}
}
int main() {
for (int i = 2; i <= N - 10; i ++)
for (int j = i; j <= N - 10; j += i)
divs[j].push_back(i);
int T = read();
while (T --) solve();
return 0;
}