CF1422F Boring Queries

Mobius127

2021-11-03 13:09:13

Solution

[题传](https://www.luogu.com.cn/problem/CF1422F) 简化题意:在线区间 $\operatorname{lcm}$。 显然不能直接上线段树,因为 $\operatorname{lcm}$ 只增不减,在这种情况下直接开高精都是不可行的,($10^5$ 个 $10^8$ 级别的数乘起来稳定飞天),所以我们考虑分开算每个质因子的贡献。 设素数集 $P=\{p_1, p_2, \dots p_m \}$,则序列中的数 $a_i$ 可表示成: $$\prod_{j=1}^m p_j^{c_{i, j}}$$ 记 $C_j =\max_{i=l}^r c_{i, j}$, 那么根据定义,区间最小公倍数为: $$\prod_{j=1}^m p_j^{C_j}$$ 大眼观察 $Max_{a}=2 \times 10^5$,由于任何数只会有一个大于 $\sqrt{Max_{a}} \approx 450$ 的素数,打表后发现这个范围内只有 $87$ 个素数,显然根号分治了: - 对于 $\le 450$ 的质因子,预处理 ST 表,每次询问暴力枚举质因子,空间复杂度 $O(87 n \log n)$,时间复杂度 $O(87n+87 \log \log n + 87q)$。 - 对于大于 $\ge 450$ 的质因子,由于只有一个,令 $b_i$ 为 $a_i$ 的最大值因子,那么就是求区间内不同种类数的乘积,类似于 [ HH 的项链 ](https://www.luogu.com.cn/problem/P1972) 这题的在线做法,用主席树,每次把上一次出现的 $b$ 拔掉即可,空间复杂度 $O(n \log n)$,时间复杂度 $O((n+q) \log n)$。 大概算了一下 ST 表空间会被卡,改成 `char` 类即可。 ```cpp const int mo=1e9+7; const int N=1e5+5; const int R=450; const int Pcnt=87; int Su[Pcnt]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449}; int n, m, Lg[N], a[N], pre[N*2], root[N], Mi[Pcnt][18]; char f[Pcnt][N][18]; namespace ZQF_AKIOI_LH_AKCTSC_CHT_AKWC{ int tot; struct node{int pro, lc, rc;}d[N*40]; #define ls d[k].lc #define rs d[k].rc #define mid (l+r>>1) void pushup(int k){d[k].pro=1ll*d[ls].pro*d[rs].pro%mo;} void build(int &k, int l, int r){ k=++tot;d[k].pro=1; if(l==r){d[k].pro=a[l&r];return ;} build(ls, l, mid), build(rs, mid+1, r); pushup(k); } void insert(int &k, int l, int r, int x, int v){ d[++tot]=d[k];k=tot; if(l==r){d[k].pro=v;return ;} if(x<=mid) insert(ls, l, mid, x, v); else insert(rs, mid+1, r, x, v); pushup(k); } int query(int k, int l, int r, int x, int y){ if((!k)||l>y||r<x) return 1; if(x<=l&&r<=y) return d[k].pro; return 1ll*query(ls, l, mid, x, y)*query(rs, mid+1, r, x, y)%mo; } #undef ls #undef rs #undef mid } int query(int j, int l, int r){ int k=Lg[r-l+1]; return max(f[j][l][k], f[j][r-(1<<k)+1][k]); } signed main(){ n=read();Lg[0]=-1; for(int i=1; i<=n; i++){ a[i]=read();Lg[i]=Lg[i>>1]+1; for(int j=0; j<Pcnt; j++) while(a[i]%Su[j]==0) f[j][i][0]++, a[i]/=Su[j]; } ZQF_AKIOI_LH_AKCTSC_CHT_AKWC :: build(root[0], 1, n); for(int i=1; i<=n; i++){ root[i]=root[i-1];if(a[i]==1) continue; if(pre[a[i]]) ZQF_AKIOI_LH_AKCTSC_CHT_AKWC :: insert(root[i], 1, n, pre[a[i]], 1); pre[a[i]]=i; } for(int k=0; k<Pcnt; k++){ for(int j=1; j<18; j++) for(int i=1; i+(1<<j)-1<=n; i++) f[k][i][j]=max(f[k][i][j-1], f[k][i+(1<<j-1)][j-1]); Mi[k][0]=1; for(int i=1; i<18; i++) Mi[k][i]=1ll*Mi[k][i-1]*Su[k]%mo; } m=read();int last=0; for(int i=1; i<=m; i++){ int l=(read()%n+last%n)%n+1, r=(read()%n+last%n)%n+1;if(l>r) swap(l, r);last=1; for(int j=0; j<Pcnt; j++){ int x=query(j, l, r); last=1ll*last*Mi[j][x]%mo; } last=1ll*last*(ZQF_AKIOI_LH_AKCTSC_CHT_AKWC :: query(root[r], 1, n, l, r))%mo; printf("%d\n", last); } return 0; } ```