【题解】CF1422F Boring Queries

(operatorname{lcm}) 能被区间内的每个数整除。考虑一个质数 (p),它在 (a_i~(lle ile r)) 中的次数(质因数分解后 (p) 的指数)一定小于等于它在 (operatorname{lcm}) 中的次数。那么可以把 (operatorname{lcm}) 表示成 (prodlimits_{p ext{ 是质数}}p^{max{cnt_{i,p}}(lle ile r)}),其中 (cnt_{i,p}) 表示 (a_i)(p) 的次数。

考虑根号分治。小于 (450) 的质数有 (87) 个,这些可以用 (87) 个 st 表做。

我们知道一个数 (x) 最多有一个大于 (sqrt x) 的质因子。把每个 (a_i) 中小于 (450) 的质因子全部除掉,剩下的是 (1) 或大于 (450) 的质数。

现在问题变成了求区间 ([l,r]) 中出现过的数的乘积(重复的只算一次)。设 (pre_i) 表示 ([1,i-1])(a_i) 最后一次出现的位置,没有出现则为 (0)。这个可以 (O(n)) 求。

对于一个 (i~(lle ile r)),若 (lle pre_i),说明 ([l,i-1]) 中出现了一个与 (a_i) 相等的数,那么这个 (i) 是不能算贡献的。

问题又变成了 (prodlimits_{i=l}^r[pre_ile l-1]a_i)。考虑建 (n) 棵线段树,第 (j) 棵维护满足 (pre_ile j) 的数的乘积((pre_i>j) 的位置上都为 (1))。容易发现对于 (j~(j>0)),最多存在一个 (i) 满足 (pre_i=j),也就是说从第 (j-1~(j>0)) 棵线段树到第 (j) 棵,最多只用修改一个数。那么可以用主席树做。

整体思路:

  1. 线性筛求质数
  2. 计算每个数中各个质数的次数并把它们除掉
  3. 建 ST 表
  4. 建主席树
  5. 回答询问

下面是代码((pre) 没有用数组记录下来)

#include <cstdio>

using namespace std;

typedef long long ll;
inline int max(int x, int y) {return x > y ? x : y;}
inline int min(int x, int y) {return x < y ? x : y;}
inline void swap(int &x, int &y) {x ^= y ^= x ^= y;}
#define rei register int
#define rep(i, l, r) for(rei i = l, i##end = r; i <= i##end; ++i)
#define per(i, r, l) for(rei i = r, i##end = l; i >= i##end; --i)
#define ci const int
char inputbuf[1 << 23], *p1 = inputbuf, *p2 = inputbuf;
#define getchar() (p1 == p2 && (p2 = (p1 = inputbuf) + fread(inputbuf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
inline int read() {
	int res = 0; char ch = getchar(); bool f = true;
	for(; ch < '0' || ch > '9'; ch = getchar())
		if(ch == '-') f = false;
	for(; ch >= '0' && ch <= '9'; ch = getchar())
		res = res * 10 + (ch ^ 48);
	return f ? res : -res;
}
const int N = 2e5 + 15, SQRT = 450, P = 1e9 + 7;
int n, a[N], b[N], rt[N], tot, lg[N], lc[N * 20], rc[N * 20], pos[N * 2], pr[SQRT], cnt;
bool npr[SQRT];
char st[90][N][18];
ll mul[N * 18], poww[100][20];

inline void upd(int p) {
	mul[p] = mul[lc[p]] * mul[rc[p]] % P;
}

void get_prime() {
	npr[1] = 1;
	rep(i, 2, SQRT - 1) {
		if(!npr[i]) pr[++ cnt] = i;
		for(rei j = 1; j <= cnt && i * pr[j] < SQRT; ++ j) {
			npr[i * pr[j]] = 1;
			if(i % pr[j] == 0) break;
		}
	}
}

inline int query(int k, int l, int r) {
	int p = lg[r - l + 1];
	return max(st[k][l][p], st[k][r - (1 << p) + 1][p]);
}

int build(int l, int r) {
	int p = ++ tot, mid = l + r >> 1;
	mul[p] = 1;
	if(l == r) return p;
	lc[p] = build(l, mid);
	rc[p] = build(mid + 1, r);
	return p;
}

void modify(int p, int l, int r, ci &t, ci &x) {
	if(l == r) { mul[p] = x; return ; }
	int mid = l + r >> 1;
	if(t <= mid) modify(lc[p], l, mid, t, x);
	else modify(rc[p], mid + 1, r, t, x);
	upd(p);
}

int modify2(int rt, int l, int r, ci &t, ci &x) {
	int p = ++ tot, mid = l + r >> 1;
	if(l == r) { mul[p] = x; return p; }
	if(t <= mid) lc[p] = modify2(lc[rt], l, mid, t, x), rc[p] = rc[rt];
	else rc[p] = modify2(rc[rt], mid + 1, r, t, x), lc[p] = lc[rt];
	upd(p);
	return p;
}

ll query(int p, int l, int r, ci &tl, ci &tr) {
	if(tl <= l && r <= tr) return mul[p];
	int mid = l + r >> 1;
	ll res = 1;
	if(tl <= mid) res = query(lc[p], l, mid, tl, tr);
	if(mid < tr) res = res * query(rc[p], mid + 1, r, tl, tr) % P;
	return res;
}

void input() {
	n = read();
	rep(i, 1, n) {
		a[i] = read();
		rep(j, 1, cnt)
			while(a[i] % pr[j] == 0) {
				a[i] /= pr[j];
				st[j][i][0] ++ ;
			}
	}
}

void build_st() {
	rep(i, 2, n) lg[i] = lg[i / 2] + 1;
	rep(k, 1, cnt) rep(j, 1, lg[n])
		for(rei i = 1; i + (1 << j) - 1 <= n; ++ i)
			st[k][i][j] = max(st[k][i][j - 1], st[k][i + (1 << j - 1)][j - 1]);
}

void build_sgt() {
	rt[0] = build(1, n);
	rep(i, 1, n) {
		if(!pos[a[i]]) modify(rt[0], 1, n, i, a[i]);
		else b[pos[a[i]]] = i;
		pos[a[i]] = i;
	}
	rep(i, 1, n) {
		if(b[i]) rt[i] = modify2(rt[i - 1], 1, n, b[i], a[b[i]]);
		else rt[i] = rt[i - 1];
	}
}

void solve() {
	int l, r;
	ll ans = 0;
	rep(i, 1, cnt) {
		poww[i][0] = 1;
		rep(j, 1, 20) poww[i][j] = (poww[i][j - 1] * pr[i]) % P;
	}
	for(int q = read(); q; -- q) {
		l = (read() + ans) % n + 1;
		r = (read() + ans) % n + 1;
		if(l > r) swap(l, r);
		ans = 1;
		rep(i, 1, cnt) ans = ans * poww[i][query(i, l, r)] % P;
		ans = ans * query(rt[l - 1], 1, n, l, r) % P;
		printf("%lld
", ans);
	}
}

signed main() {
	get_prime();
	input();
	build_st();
	build_sgt();
	solve();
	return 0;
}
原文地址:https://www.cnblogs.com/creating-2007/p/14588177.html