zoukankan      html  css  js  c++  java
  • 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(nsqrt{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
    ",ans[i]);
    }
    
    int main(){work();return 0;}
    
    
  • 相关阅读:
    Search Insert Position
    lintcode: 最长连续序列
    lintcode:颜色分类
    lintcode: 堆化
    lintcode: 旋转图像
    lintcode: 寻找旋转排序数组中的最小值
    lintcode: 跳跃游戏 II
    lintcode:最小差
    华为:数独填充
    华为:字符集合
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7622796.html
Copyright © 2011-2022 走看看