CF1516D 题解
HHH6666666666 · · 个人记录
一个非倍增的做法。
考虑如何处理一个询问。显然一个区间合法的充要条件是其中不能出现两个拥有相同质因子的数。由此,右端点一定时左端点越靠右答案越优。进一步想到贪心策略:从左端点起向右找到最靠右的合法右端点,以这两个端点作为一个区间,然后考虑下一个数。重复直到到达右端点。
因此,对于一个固定的点
不难发现
复杂度
代码如下:
#include<bits/stdc++.h>
#define ep emplace
#define eb emplace_back
using namespace std;
const int MAXN = 1e5 + 10;
int n, Q;
int a[MAXN];
vector<int> to[MAXN];
int L[MAXN], R[MAXN], idx;
struct BITree {
int a[MAXN];
#define lowbit(x) ((x) & (-(x)))
void add(int x, int k) {
for (int i = x; i <= n + 1; i += lowbit(i))
a[i] += k;
return;
}
int query(int x) {
int res = 0;
for (int i = x; i; i -= lowbit(i))
res += a[i];
return res;
}
} tr;
vector<int> spl[MAXN];
struct Query {
int id, l, r, ans;
} q[MAXN];
vector<int> v[MAXN];
void dfs(int x) {
L[x] = ++idx;
for (int y : to[x]) dfs(y);
R[x] = idx;
return;
}
vector<int> split(int x) {
vector<int> v;
for (int i = 2; i * i <= x; ++i) {
if (x % i == 0) {
v.eb(i);
while (x % i == 0) x /= i;
}
}
if (x > 1) v.eb(x);
return v;
}
int main() {
ios:: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> Q;
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = 1; i <= n; ++i)
spl[i] = split(a[i]);
int nowans = n + 1;
for (int i = n; i; --i) {
for (auto j : spl[i]) {
v[j].eb(i);
if (v[j].size() > 1) nowans = min(nowans, v[j][v[j].size() - 2]);
}
to[nowans].eb(i);
}
for (int i = 1; i <= Q; ++i) {
q[i].id = i;
cin >> q[i].l >> q[i].r;
}
sort(q + 1, q + Q + 1, [] (Query x, Query y) { return x.r < y.r; });
dfs(n + 1);
int now = 1;
for (int i = 1; i <= Q; ++i) {
int l = q[i].l, r = q[i].r;
while (now <= r) {
assert(L[now]);
tr.add(L[now], 1), tr.add(R[now] + 1, -1), ++now;
}
q[i].ans = tr.query(L[l]);
}
sort(q + 1, q + Q + 1, [] (Query x, Query y) { return x.id < y.id; });
for (int i = 1; i <= Q; ++i)
cout << q[i].ans << endl;
return 0;
}