51nod 1203 JZPLCM

本文介绍了一种利用质因数分解和RMQ算法解决特定数学问题的方法。通过将质因子分为小于和大于根号n两部分,并分别采用RMQ算法和莫队算法进行处理,最终实现了高效的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接.

据说这是某国家队爷的题,怪不得我一眼不会。

求lcm即求各个质因子对应得指数的最大值。

这时候想到以前做过几道类似的题怎么做的。

<n 的质因子分成一块,大于 >n 的质因子分成一块。

这样做的优势是 <n 的质因子的个数少,
而, >n 的质因子的指数最大为1。

那么这道题就显然了。

<n 的质因子强行RMQ,因为只有48个。

>n 的质因子因为指数小于等于1,可以直接上莫队,提前处理一下逆元就好了。

时间复杂度 O(48n log n+nn)

Code:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
using namespace std;

const int N = 50005, M = 223;

int bz[N], p[N], zp[N];


void Shai() {
    fo(i, 2, 5e4) {
        if(!bz[i]) p[++ p[0]] = i;
        fo(j, 1, p[0]) {
            if(i * p[j] > 5e4) break;
            bz[i * p[j]] = 1;
            if(i % p[j] == 0) break;
        }
    }
    int t = 0;
    fo(i, 2, 5e4) if(!bz[i])
        zp[i] = ++ t;
}

int num[N];

void Build() {
    int tot = 0;
    fo(i, 1, 5e4) {
        num[i] = num[i - 1];
        if((i - 1) % M == 0) num[i] ++;
    }
}

int n, Q, x, y, a[N], p0[N], u[N][20], v[N][20];

struct Ask {
    int l, r, i;
} c[N];

void fen(int a, int x) {
    p0[a] = 0;
    for(int i = 1; i <= p[0] && p[i] * p[i] <= x; i ++) {
        if(x % p[i] == 0) {
            u[a][++ p0[a]] = i;
            v[a][p0[a]] = 0;
            while(x % p[i] == 0)
                x /= p[i], v[a][p0[a]] ++;
        }
    }
    if(x > 1) {
        u[a][++ p0[a]] = zp[x];
        v[a][p0[a]] = 1;
    }
}

bool rank_c(Ask a, Ask b) {
    if(num[a.l] < num[b.l]) return 1;
    if(num[a.l] > num[b.l]) return 0;
    return a.r < b.r;
}


int f[16][N], a2[16];

int query(int i, int j) {
    int lg = log2(j - i + 1);
    return max(f[lg][i], f[lg][j - a2[lg] + 1]);
}

const int mo = 1e9 + 7;

ll ksm(ll x, ll y) {
    ll s = 1;
    for(; y; y >>= 1, x = x * x % mo)   
        if(y & 1) s = s * x % mo;
    return s;
}

ll ni[N], ans[N];

ll sum;

int t[N];

void add(int x, int y) {
    t[x] += y;
    if(t[x] == 0) sum = sum * ni[x] % mo;
    if(t[x] == 1 && y == 1) sum = sum * p[x] % mo;
}

void chan(int x) {
    int k = bz[x] ? -1 : 1; bz[x] = !bz[x];
    fo(i, 1, p0[x]) if(u[x][i] > 48)
        add(u[x][i], k);
}

int main() {
    Shai();
    Build();
    scanf("%d %d", &n, &Q);
    fo(i, 1, n) scanf("%d", &a[i]), fen(i, a[i]);
    fo(i, 1, Q) scanf("%d %d", &c[i].l, &c[i].r), c[i].i = i;
    fo(i, 1, Q) ans[i] = 1;
    a2[0] = 1; fo(i, 1, 15) a2[i] = a2[i - 1] * 2;
    fo(k, 1, 48) {
        fo(i, 1, n) f[0][i] = 0;
        fo(i, 1, n) fo(j, 1, p0[i])
            if(u[i][j] == k) f[0][i] = v[i][j];
        fo(j, 1, 15) fo(i, 1, n) f[j][i] = max(f[j - 1][i], f[j - 1][min(i + a2[j - 1], n)]);
        fo(i, 1, Q) ans[i] = ans[i] * ksm(p[k], query(c[i].l, c[i].r)) % mo;
    }
    sort(c + 1, c + Q + 1, rank_c);
    fo(i, 1, p[0]) ni[i] = ksm(p[i], mo - 2);
    memset(bz, 0, sizeof(bz));
    int x = 1, y = 0; sum = 1;
    fo(i, 1, Q) {
        while(x < c[i].l) chan(x ++);
        while(x > c[i].l) chan(-- x);
        while(y < c[i].r) chan(++ y);
        while(y > c[i].r) chan(y --);
        ans[c[i].i] = ans[c[i].i] * sum % mo;
    }
    fo(i, 1, Q) printf("%lld\n", ans[i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值