CF1422F Boring Queries
给定一个长度为 n n n的数组 a , ( 1 ≤ a i ≤ 2 × 1 0 5 ) a,(1 \leq a_i \leq 2 \times 10 ^ 5) a,(1≤ai≤2×105),有 m m m次询问,每次询问给定 l , r l, r l,r,要我们求区间 [ l , r ] [l, r] [l,r], a i a_i ai的 l c m lcm lcm,强制在线。
对于质因子 p p p,如果 p 2 > 2 × 1 0 5 p ^ 2 > 2 \times 10 ^ 5 p2>2×105,那么它在每个数中出现的次数只有两种可能 0 / 1 0/1 0/1,可以如HH的项链的那题,一样对每个因子维护一个最后出现的乘积。
如果 p 2 ≤ 2 × 1 0 5 p ^ 2 \leq 2 \times 10 ^ 5 p2≤2×105,我们可以考虑用 R M Q RMQ RMQ表来维护区间最大值,容易知道最多只要维护 86 86 86个 R M Q RMQ RMQ表,所以整体复杂度 O ( 86 × n log n ) O(86 \times n \log n) O(86×nlogn)。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = 2e5 + 10, mod = 1e9 + 7;
int root[N], ls[N * 40], rs[N * 40], sum[N * 40], num;
int prime[N], Log[N], inv[M], pre[M], fac[M], a[N], cnt, n, m;
vector<int> p[87];
bool st[M];
struct RMQ {
char f[N][18];
void init() {
for (int j = 1; j < 18; j++) {
for (int i = 1; i + (1 << j) - 1 <= n; i++) {
f[i][j] = max(f[i][j - 1], f[i + (1 << j - 1)][j - 1]);
}
}
}
int query(int l, int r) {
int s = Log[r - l + 1];
return max(f[l][s], f[r - (1 << s) + 1][s]);
}
}rmq[87];
void init() {
inv[1] = 1;
for (int i = 2; i < M; i++) {
inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
if (!st[i]) {
prime[++cnt] = i;
}
for (int j = 1; j <= cnt && 1ll * i * prime[j] < M; j++) {
st[i * prime[j]] = 1;
if (i % prime[j] == 0) {
break;
}
}
}
for (int i = 2; i < N; i++) {
Log[i] = Log[i / 2] + 1;
}
for (int j = 1; prime[j] * prime[j] < M; j++) {
for (int i = 1; i <= n; i++) {
while (a[i] % prime[j] == 0) {
a[i] /= prime[j];
rmq[j].f[i][0]++;
}
}
rmq[j].init();
for (int cur = 1; cur < M; cur *= prime[j]) {
p[j].push_back(cur);
}
}
for (int i = 87; i <= cnt; i++) {
for (int j = prime[i]; j < M; j += prime[i]) {
fac[j] = prime[i];
}
}
}
void build(int &rt, int l, int r) {
rt = ++num;
if (l == r) {
sum[rt] = 1;
return ;
}
int mid = l + r >> 1;
build(ls[rt], l, mid);
build(rs[rt], mid + 1, r);
sum[rt] = sum[ls[rt]] * sum[rs[rt]];
}
void update(int &rt, int pre, int l, int r, int x, int v) {
rt = ++num, ls[rt] = ls[pre], rs[rt] = rs[pre], sum[rt] = 1ll * sum[pre] * v % mod;
if (l == r) {
return ;
}
int mid = l + r >> 1;
if (x <= mid) {
update(ls[rt], ls[pre], l, mid, x, v);
}
else {
update(rs[rt], rs[pre], mid + 1, r, x, v);
}
}
int query(int rt, int l, int r, int L, int R) {
if (l >= L && r <= R) {
return sum[rt];
}
int ans = 1, mid = l + r >> 1;
if (L <= mid) {
ans = 1ll * ans * query(ls[rt], l, mid, L, R) % mod;
}
if (R > mid) {
ans = 1ll * ans * query(rs[rt], mid + 1, r, L, R) % mod;
}
return ans;
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
init();
build(root[0], 1, n);
for (int i = 1; i <= n; i++) {
root[i] = root[i - 1];
if (!fac[a[i]]) {
continue;
}
update(root[i], root[i], 1, n, i, fac[a[i]]);
if (pre[fac[a[i]]]) {
update(root[i], root[i], 1, n, pre[fac[a[i]]], inv[fac[a[i]]]);
}
pre[fac[a[i]]] = i;
}
scanf("%d", &m);
int ans = 0;
for (int i = 1, l, r; i <= m; i++) {
scanf("%d %d", &l, &r);
l = (ans + l) % n + 1, r = (ans + r) % n + 1;
if (l > r) {
swap(l, r);
}
ans = 1;
for (int j = 1; j <= 86; j++) {
ans = 1ll * ans * p[j][rmq[j].query(l, r)] % mod;
}
ans = 1ll * ans * query(root[r], 1, n, l, r) % mod;
printf("%d\n", ans);
}
return 0;
}