CodeForces 2094H La Vaca Saturno Saturnita 题解
注意到每次 \(k\) 除以一个大于 \(1\) 的数至少减半,所以一次查询中 \(k\) 至多变化 \(\log V\) 次。
把相同的 \(k\) 一起处理,重新描述 f(k, a, l, r):
- 设当前位置为 \(x\),初始 \(x = l\);
- 每次移动到最小的 \(x < y \leqslant r\),使得 \(a_y \mid k, a_y \ne 1\),如果不存在则规定 \(y = r + 1\);
- 向答案贡献 \(k \cdot (y - x)\);
- \(x \leftarrow y\),重复上述操作直到 \(x > r\)。
只需要快速求出 \(y\),根号分治,设阈值 \(B\),考虑 \(x\) 的约数 \(d\):
- 若 \(d \leqslant B\),预处理 \(nxt_{i, j}\) 表示 \(i\) 之后第一个 \(j\) 的位置即可;
- 若 \(d > B\),预处理 \(pos_x\) 表示 \(x\) 的所有这样的约数在数组中出现过的位置,二分即可。
时间复杂度 \(O(\frac {nV} B + q \log V (B + \log n))\),常数极小。\(B = \frac n {\sqrt{q \log n}}\) 时取到最小值 \(O(n \sqrt{q \log V} + q \log n \log V)\)。实际上 \(B\) 稍微取大一点更优。
@modfisher 大神指出可以离线避免二分。
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
typedef long long i64;
const int lim = 1e5;
const int B = 200;
vector<int> divs[lim + 5];
int n, q;
int a[100005];
vector<int> pos[100005];
int nxt[100005][B + 5];
static inline void solve() {
cin >> n >> q;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
if (a[i] > B)
for (int j = a[i]; j <= lim; j += a[i])
pos[j].push_back(i);
}
for (int i = 1; i <= B; ++i)
nxt[n + 1][i] = n + 1;
for (int i = n; i; --i) {
for (int j = 1; j <= B; ++j)
nxt[i][j] = nxt[i + 1][j];
if (a[i] <= B)
nxt[i][a[i]] = i;
}
while (q--) {
int k, l, r;
cin >> k >> l >> r;
i64 ans = 0;
for (int x = l;;) {
int to = r + 1;
for (auto d : divs[k]) {
if (d > B)
break;
to = min(to, nxt[x][d]);
}
auto it = lower_bound(pos[k].begin(), pos[k].end(), x);
if (it != pos[k].end())
to = min(to, *it);
ans += 1ll * (to - x) * k;
// cerr << " " << k << " jump " << x << " -> " << to << " | gain " << (to - x) * k << endl;
x = to;
if (x > r)
break;
while (k % a[x] == 0)
k /= a[x];
}
cout << ans << '\n';
}
for (int i = 1; i <= n; ++i)
if (a[i] > B)
for (int j = a[i]; j <= lim; j += a[i])
pos[j].clear();
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
for (int i = 2; i <= lim; ++i)
for (int j = i; j <= lim; j += i)
divs[j].push_back(i);
int T;
cin >> T;
while (T--)
solve();
return 0;
}

浙公网安备 33010602011771号