CF1422F Boring Queries

· · 题解

题传

简化题意:在线区间 \operatorname{lcm}

显然不能直接上线段树,因为 \operatorname{lcm} 只增不减,在这种情况下直接开高精都是不可行的,(10^510^8 级别的数乘起来稳定飞天),所以我们考虑分开算每个质因子的贡献。

设素数集 P=\{p_1, p_2, \dots p_m \},则序列中的数 a_i 可表示成:

\prod_{j=1}^m p_j^{c_{i, j}}

C_j =\max_{i=l}^r c_{i, j}

那么根据定义,区间最小公倍数为:

\prod_{j=1}^m p_j^{C_j}

大眼观察 Max_{a}=2 \times 10^5,由于任何数只会有一个大于 \sqrt{Max_{a}} \approx 450 的素数,打表后发现这个范围内只有 87 个素数,显然根号分治了:

大概算了一下 ST 表空间会被卡,改成 char 类即可。

const int mo=1e9+7;
const int N=1e5+5;
const int R=450;
const int Pcnt=87;
int Su[Pcnt]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449};
int n, m, Lg[N], a[N], pre[N*2], root[N], Mi[Pcnt][18];
char f[Pcnt][N][18];
namespace ZQF_AKIOI_LH_AKCTSC_CHT_AKWC{
    int tot;
    struct node{int pro, lc, rc;}d[N*40];
    #define ls d[k].lc
    #define rs d[k].rc
    #define mid (l+r>>1)
    void pushup(int k){d[k].pro=1ll*d[ls].pro*d[rs].pro%mo;}
    void build(int &k, int l, int r){
        k=++tot;d[k].pro=1;
        if(l==r){d[k].pro=a[l&r];return ;}
        build(ls, l, mid), build(rs, mid+1, r);
        pushup(k);
    }
    void insert(int &k, int l, int r, int x, int v){
        d[++tot]=d[k];k=tot;
        if(l==r){d[k].pro=v;return ;}
        if(x<=mid) insert(ls, l, mid, x, v);
        else insert(rs, mid+1, r, x, v);
        pushup(k);
    }
    int query(int k, int l, int r, int x, int y){
        if((!k)||l>y||r<x) return 1;
        if(x<=l&&r<=y) return d[k].pro;
        return 1ll*query(ls, l, mid, x, y)*query(rs, mid+1, r, x, y)%mo;
    }
    #undef ls
    #undef rs
    #undef mid
}
int query(int j, int l, int r){
    int k=Lg[r-l+1];
    return max(f[j][l][k], f[j][r-(1<<k)+1][k]);
}
signed main(){
    n=read();Lg[0]=-1;
    for(int i=1; i<=n; i++){
        a[i]=read();Lg[i]=Lg[i>>1]+1;
        for(int j=0; j<Pcnt; j++)
            while(a[i]%Su[j]==0) f[j][i][0]++, a[i]/=Su[j];
    }
    ZQF_AKIOI_LH_AKCTSC_CHT_AKWC :: build(root[0], 1, n);
    for(int i=1; i<=n; i++){
        root[i]=root[i-1];if(a[i]==1) continue;
        if(pre[a[i]]) ZQF_AKIOI_LH_AKCTSC_CHT_AKWC :: insert(root[i], 1, n, pre[a[i]], 1);
        pre[a[i]]=i;
    }
    for(int k=0; k<Pcnt; k++){
        for(int j=1; j<18; 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]);
        Mi[k][0]=1;
        for(int i=1; i<18; i++) Mi[k][i]=1ll*Mi[k][i-1]*Su[k]%mo;
    }
    m=read();int last=0;
    for(int i=1; i<=m; i++){
        int l=(read()%n+last%n)%n+1, r=(read()%n+last%n)%n+1;if(l>r) swap(l, r);last=1;
        for(int j=0; j<Pcnt; j++){
            int x=query(j, l, r);
            last=1ll*last*Mi[j][x]%mo;
        }
        last=1ll*last*(ZQF_AKIOI_LH_AKCTSC_CHT_AKWC :: query(root[r], 1, n, l, r))%mo;
        printf("%d\n", last);
    }
    return 0;
}