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;}

posted @ 2017-10-02 22:03  PIPIBoss  阅读(151)  评论(0编辑  收藏  举报