原题链接:https://codeforces.ml/contest/1516/problem/D
题意
给定一个n个元素的序列,每次询问一个区间[l,r],问区间内最少可以划分成多少块,使得块内的所有数互质
分析
首先所有数互质可以想到所有的质因子都不能相同,因此我们对每个数进行质因数分解并记录这些质因子最后出现的位置,然后再利用倍增的思想预处理出倍增数组记录每个位置往前跳的位置,这样复杂度可以控制在logn*m。
查询的时候就一直暴力往前跳就可以,如果大于左端点,那么答案就加上跳过的块数。
Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <bitset>
#include <map>
#include <set>
#include <stack>
#include <queue>
//#include <unordered_map>
using namespace std;
#define fi first
#define se second
#define re register
typedef long long ll;
typedef pair<ll, ll> PII;
typedef unsigned long long ull;
const int N = 5e5 + 10, M = 1e6 + 5, INF = 0x3f3f3f3f;
const int MOD = 1e9+7;
int pre[N][20], lst[N], pos[N];
void solve() {
int n, m; cin >> n >> m;
for (int i = 1; i <= n; i++) {
int x; cin >> x;
lst[i] = lst[i-1];
for (int j = 2; j * j <= x; j++) {
if (x % j == 0) {
lst[i] = max(lst[i], pos[j]);
while (x % j == 0) x /= j;
pos[j] = i;
}
}
if (x > 1) {
lst[i] = max(lst[i], pos[x]);
pos[x] = i;
}
pre[i][0] = lst[i];
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j < 20; j++) {
pre[i][j] = pre[pre[i][j-1]][j-1];
}
}
while (m--) {
int l, r; cin >> l >> r;
int now = r, ans = 0;
for (int i = 19; ~i; i--) {
if (pre[now][i] >= l) {
ans += (1 << i);
now = pre[now][i];
}
}
cout << ans + 1 << endl;
}
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifdef ACM_LOCAL
freopen("input", "r", stdin);
freopen("output", "w", stdout);
#endif
solve();
return 0;
}