51Nod 1203 JZPLCM
题目描述
长度为N的正整数序列S,有Q次询问,每次询问一段区间内所有数的lcm(即最小公倍数)。由于答案可能很大,输出答案Mod 10^9 + 7。
例如:2 3 4 5,询问[1,3]区间的最小公倍数为2 3 4的最小公倍数 = 12。
解题报告:
用时:1h30min,4WA
这题数据范围比较小可以直接乱来,根据常识\(>sqrt(N)\)的质因子最多的次数最多为1,所以对于\(>sqrt(N)\)的部分可以直接用桶+莫队来判断是否出现即可。
然后就是小于的部分:
\(lcm=q1^{k1}*q2^{k2}...*qn^{kn}\)
\(ki\)是每一个含有\(qi\)的元素最大次项
可以直接线段树之类的或者st表维护一下区间最大值,这题最好还是st表,为了防止MLE,st表要开short。
复杂度:\(O(n\sqrt{n}logn)\)
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=50005,mod=1e9+7;
struct node{
int l,r,bo,id;
bool operator <(const node &pr)const{
if(bo!=pr.bo)return bo<pr.bo;
return r<pr.r;
}
}q[N];
int n,m,block,s[N],num=0,li=224,pri[N],maxdep,bi[N];bool vis[N];
short f[49][N][20];
ll mul[N][30],tot=1,ans[N],ni[N];
void priwork(){
for(int i=2;i<=li;i++){
if(!vis[i])pri[++num]=i;
for(int j=1;j<=num && pri[j]*i<=li;j++){
vis[i*pri[j]]=true;if(i%pri[j]==0)break;
}
}
}
void midit(int i){
int cnt=0,x=s[i];
for(int j=1;j<=num;j++){
if(pri[j]>x)break;
cnt=0;
while(x%pri[j]==0)x/=pri[j],cnt++;
f[j][i][0]=cnt;
}
if(x>1)bi[i]=x;
}
ll qm(ll x,ll k){
ll sum=1;
while(k){
if(k&1)sum*=x,sum%=mod;
x*=x;x%=mod;k>>=1;
}
return sum;
}
int t[N];
void add(int x){
if(bi[x]){if(!t[bi[x]])tot*=bi[x],tot%=mod;t[bi[x]]++;}
}
void delet(int x){
if(bi[x]){t[bi[x]]--;if(!t[bi[x]])tot*=ni[bi[x]],tot%=mod;}
}
int query(int l,int r,int x){
int k=log(r-l+1)/log(2);
return mul[pri[x]][Max(f[x][l][k],f[x][r-(1<<k)+1][k])];
}
void work()
{
scanf("%d%d",&n,&m);
block=sqrt(n);priwork();maxdep=log(n)/log(2)+1;
for(int i=1;i<=n;i++)scanf("%d",&s[i]);
for(int i=1;i<=m;i++){
scanf("%d%d",&q[i].l,&q[i].r);
q[i].bo=q[i].l/block;q[i].id=i;
}
sort(q+1,q+m+1);
for(int i=1;i<=n;i++)midit(i);
for(int k=1;k<=num;k++)
for(int j=1;j<=maxdep;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]);
for(int i=1;i<li;i++){
mul[i][0]=1;
for(int j=1;j<30;j++)(mul[i][j]=mul[i][j-1]*i)%=mod;
}
ni[0]=0;
for(int i=1;i<N;i++)ni[i]=qm(i,mod-2);
int l=1,r=0;ll ret=1;
for(int i=1;i<=m;i++){
while(r<q[i].r)r++,add(r);
while(l>q[i].l)l--,add(l);
while(r>q[i].r)delet(r),r--;
while(l<q[i].l)delet(l),l++;
ret=1;
for(int j=1;j<=num;j++)ret*=query(l,r,j),ret%=mod;
ret=ret*tot%mod;ans[q[i].id]=ret;
}
for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
}
int main(){work();return 0;}