zoukankan      html  css  js  c++  java
  • 【题解】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;
    }
    
  • 相关阅读:
    创建数据库指定编码格式
    java开发环境配置
    Eclipse 配置工程
    声明式事务管理 的5 种方式
    web容器启动顺序
    2.1 实践篇:使用ping来检测网速
    1.1 mysql安装
    1.2 测试人员与开发人员比例
    1.0 软件测试能力
    1.4 测试各阶段(单元、集成、系统 、Alpha、Beta、验收)
  • 原文地址:https://www.cnblogs.com/creating-2007/p/14588177.html
Copyright © 2011-2022 走看看