LCM [树状数组, HH的项链]

L C M LCM LCM

给 你 一 个 长 度 为 N 的 数 列 , 有 M 次 询 问 , 每 次 询 问 一 段 区 间 的 L C M 模 1 e 9 + 7 的 值 . 给你一个长度为 N 的数列,有 M 次询问,每次询问一段区间的 LCM 模 1e9+7 的值 . NMLCM1e9+7.

1 ≤ N ≤ 200000   1 ≤ M ≤ 200000   1 ≤ A i ≤ 1000000 1 ≤ N ≤ 200000\ 1 ≤ M ≤ 200000\ 1 ≤ Ai ≤ 1000000 1N200000 1M200000 1Ai1000000


正 解 部 分 \color{red}{正解部分}

类似 ‘HH的项链’ 的做法,

将所有询问离线, 按 右端点 从小到大 排序, 然后 从左向右 枚举 i i i,

首先对当前位置的 A [ i ] A[i] A[i] 进行 质因数 分解, 记 l a s t [ p k ] last[p^k] last[pk] 表示 p k p^k pk 这个因子在 i i i 前面最晚出现的位置,
使用 树状数组 维护 前缀积, 若 A [ i ] A[i] A[i] 含有质因子 p m p^m pm, 则对 l a s t [ p 1 ] , l a s t [ p 2 ] . . . l a s t [ p m ] last[p^1], last[p^2]...last[p^m] last[p1],last[p2]...last[pm] 位置上的值 p p p, 使 l a s t [ p k ] = i last[p^k]=i last[pk]=i, 最后在 i i i 位置上 m m m p p p,


实 现 部 分 \color{red}{实现部分}

#include<bits/stdc++.h>
#define reg register

const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;

int N;
int M;
int pcnt;
int p[maxn];
int A[maxn];
int fm[maxn];
int Ans[maxn];
int last[maxn];

bool vis[maxn];

void sieve(){
        for(reg int i = 2; i < maxn; i ++){
                if(!vis[i]) p[++ pcnt] = i, fm[i] = i;
                for(reg int j = 1; j <= pcnt && i*p[j] < maxn; j ++){
                        vis[i*p[j]] = 1; fm[i*p[j]] = p[j];
                        if(i % p[j] == 0) break ;
                }
        }
}

int Ksm(int a, int b){int s=1;while(b){ if(b&1)s=1ll*s*a%mod;a=1ll*a*a%mod;b>>=1; }return s;}

struct Que{ int l, r, id; } que[maxn];

struct Bit_Tree{
        int v[maxn], lim;
        void Add(int k, int x){ while(k<=lim)v[k]=1ll*v[k]*x%mod,k+=k&-k; }
        int Query(int k){ if(k<=0) return 1; int s=1; while(k)s=1ll*s*v[k]%mod,k-=k&-k; return s; }
} bit_t;

bool cmp(Que a, Que b){ return a.r < b.r; }

int main(){
        sieve();
        scanf("%d%d", &N, &M); bit_t.lim = N;
        for(reg int i = 1; i <= N; i ++) scanf("%d", &A[i]), bit_t.v[i] = 1;
        for(reg int i = 1; i <= M; i ++) scanf("%d%d", &que[i].l, &que[i].r), que[i].id = i;
        std::sort(que+1, que+M+1, cmp); int t = 1;
        for(reg int i = 1; i <= N; i ++){
                int x = A[i];
                while(x > 1){
                        int k = 1, p = fm[x];
                        while(x%p == 0){
                                x /= p, k *= p;
                                if(last[k]) bit_t.Add(last[k], Ksm(p, mod-2));
                                last[k] = i; bit_t.Add(i, p);
                        }
                }
                while(i == que[t].r) Ans[que[t].id] = 1ll*bit_t.Query(que[t].r)*Ksm(bit_t.Query(que[t].l-1), mod-2)%mod, t ++;
        }
        for(reg int i = 1; i <= M; i ++) printf("%d\n", Ans[i]);
        return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值