题目大意
给出一列数,求一段区间的lcm。
解题思路
离线询问,对小于sqrt(n)的质因子暴力求出,rmq解决询问。这样之后就只最多剩下一个质因子,可以使用莫队用桶维护。
code
using namespace std;
int const Mxn=5*1e4;
int N,Q,Size,A[Mxn+9],Ha[Mxn+9],Cnt[Mxn+9],F[Mxn+9][17],Two[17],Ans[Mxn+9],Mo=1e9+7;
struct Rec{int L,R,P;};
Rec B[Mxn+9];
bool Cmp(Rec X,Rec Y){
return ((X.L-1)/Size<(Y.L-1)/Size)||(((X.L-1)/Size==(Y.L-1)/Size)&&(X.R<Y.R));
}
int Pow(LL X,int Y){
LL Z=1;
while(Y){
if(Y&1)Z=Z*X%Mo;
X=X*X%Mo;
Y>>=1;
}
return Z;
}
int Calc(int L,int R){
int X=log(R-L+1)/log(2);
return Max(F[L][X],F[R-Two[X]+1][X]);
}
int main(){
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%d%d",&N,&Q);int Mx=0,Mx2=log(N)/log(2),Tmp,Ok;Size=sqrt(N);
Two[0]=1;Fo(i,1,Mx2)Two[i]=Two[i-1]<<1;
Fo(i,1,N)scanf("%d",&A[i]),Mx=Max(Mx,A[i]);Mx=sqrt(Mx);
Fo(i,1,Q)scanf("%d%d",&B[i].L,&B[i].R),B[i].P=i,Ans[i]=1;
Fo(i,2,Mx){
Tmp=sqrt(i);Ok=1;
Fo(j,2,Tmp)if(i%j==0){Ok=0;break;}
if(Ok){
Fo(j,1,N){
F[j][0]=0;
while(A[j]%i==0)F[j][0]++,A[j]/=i;
}
Fo(k,1,Mx2)Fd(j,N-Two[k-1],1)F[j][k]=Max(F[j][k-1],F[j+Two[k-1]][k-1]);
Fo(j,1,Q)Ans[j]=1ll*Ans[j]*Pow(i,Calc(B[j].L,B[j].R))%Mo;
}
}
sort(B+1,B+Q+1,Cmp);
int Next;LL Now;
Fo(i,1,Q)if(((B[i].L-1)/Size!=(B[i-1].L-1)/Size)||(i==1)){
if(B[i].P==14){
int bb;
bb++;
}
Now=1;Next=(B[i].L-1)/Size*Size+Size;
Fo(j,1,Mxn)Cnt[j]=0;
Fo(j,Next+1,B[i].R){
if(!Cnt[A[j]])Now=(Now*A[j])%Mo;
Cnt[A[j]]++;
}
LL Tmp=Now;
Fo(j,B[i].L,Min(Next,B[i].R)){
if(!Cnt[A[j]])Now=(Now*A[j])%Mo;
Cnt[A[j]]++;
}
Fo(j,B[i].L,Min(Next,B[i].R))Cnt[A[j]]--;
Ans[B[i].P]=1ll*Ans[B[i].P]*Now%Mo;Now=Tmp;
}else{
if(B[i].P==14){
int bb;
bb++;
}
Fo(j,Max(Next+1,B[i-1].R+1),B[i].R){
if(!Cnt[A[j]])Now=(Now*A[j])%Mo;
Cnt[A[j]]++;
}
LL Tmp=Now;
Fo(j,B[i].L,Min(Next,B[i].R)){
if(!Cnt[A[j]])Now=(Now*A[j])%Mo;
Cnt[A[j]]++;
}
Fo(j,B[i].L,Min(Next,B[i].R))Cnt[A[j]]--;
Ans[B[i].P]=1ll*Ans[B[i].P]*Now%Mo;Now=Tmp;
}
Fo(i,1,Q)printf("%d\n",Ans[i]);
return 0;
}