1. 程式人生 > 其它 >cf1422F. Boring Queries

cf1422F. Boring Queries

題目描述

題解

$\text{lcm}$ 可以看成質因數指數 $\max$ 的乘積。

不超過 $\sqrt{2e5}$ 的質因數最多出現一次,剩下的質因數一共 $86$ 個,可以用線段樹或 $\text{st}$ 表維護 $\text{max}$ 。

大於 $\sqrt{2e5}$ 的質因數用分塊處理答案就好了,具體就是維護塊之間的答案和每個數和它相同的數的前驅後繼即可。

效率: $O(86nlogn+n\sqrt{n})$ 。

程式碼

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5,P=1e9+7;
int n,q,p[N],t,m,a[N],pre[N],nex[N],pos[N],b[N],lb[505],rb[N],Z,h[505][505]; struct O{ int f[N<<2],w[40]; void init(int x){ w[0]=1; for (int i=1;i<40;i++) w[i]=1ll*x*w[i-1]%P; } #define Ls k<<1 #define Rs k<<1|1 #define mid ((l+r)>>1) void
upd(int k,int l,int r,int u,int v){ if (l==r){f[k]=v;return;} if (mid>=u) upd(Ls,l,mid,u,v); else upd(Rs,mid+1,r,u,v); f[k]=max(f[Ls],f[Rs]); } int qry(int k,int l,int r,int L,int R){ if (L<=l && r<=R) return f[k]; if (mid>=R) return
qry(Ls,l,mid,L,R); if (mid<L) return qry(Rs,mid+1,r,L,R); return max(qry(Ls,l,mid,L,R),qry(Rs,mid+1,r,L,R)); } }g[87]; bool vis[N]; int main(){ m=sqrt(2e5); for (int i=2;i<=m;i++){ if (!vis[i]) p[++t]=i,g[t].init(i); for (int v,j=1;j<=t;j++){ v=p[j]*i;if (v>m) break; vis[v]=1;if (i%p[j]==0) break; } } scanf("%d",&n); for (int i=1;i<=n;i++){ scanf("%d",&a[i]); for (int v,j=1;j<=t;j++){ v=0; while(a[i]%p[j]==0) a[i]/=p[j],v++; if (v) g[j].upd(1,1,n,i,v); } pre[i]=pos[a[i]];pos[a[i]]=i; } for (int i=1;i<N;i++) pos[i]=n+1; for (int i=n;i;i--) nex[i]=pos[a[i]],pos[a[i]]=i; m=sqrt(n); for (int i=1;i<=n;i++){ b[i]=(i-1)/m+1; if (b[i]!=b[i-1]) rb[b[i-1]]=i-1,lb[b[i]]=i; } rb[Z=b[n]]=n; for (int i=1;i<=Z;i++){ h[i][i-1]=1; for (int j=i;j<=Z;j++){ h[i][j]=h[i][j-1]; for (int k=lb[j];k<=rb[j];k++) if (pre[k]<lb[i]) h[i][j]=1ll*h[i][j]*a[k]%P; } } scanf("%d",&q); for (int l,r,lst=0;q--;){ scanf("%d%d",&l,&r); l=(l+lst)%n+1;r=(r+lst)%n+1; if (l>r) swap(l,r);lst=1; for (int i=1;i<=t;i++) lst=1ll*lst*g[i].w[g[i].qry(1,1,n,l,r)]%P; if (b[l]>=b[r]-1){ for (int i=l;i<=r;i++) if (pre[i]<l) lst=1ll*lst*a[i]%P; } else{ lst=1ll*lst*h[b[l]+1][b[r]-1]%P; for (int i=l;i<=rb[b[l]];i++) if (nex[i]>=lb[b[r]]) lst=1ll*lst*a[i]%P; for (int i=lb[b[r]];i<=r;i++) if (pre[i]<l) lst=1ll*lst*a[i]%P; } printf("%d\n",lst); } return 0; }