LGP5071 [Ynoi 2015-E] 此时此刻的光辉 学习笔记

LGP5071 [Ynoi 2015-E] 此时此刻的光辉 学习笔记

Luogu Link

前言

敬我的第一场ICPC,以及那模糊淡薄的珂学信仰认同。

题意简述

一个长为 \(n\) 的序列,\(m\) 次查询,每次查询一段区间的乘积的约数个数 \(\bmod\,19260817\)

\(n,m\le 10^5\)\(a_i\le 10^9\)

做法解析

看到约数个数,就令人想到了用莫队维护出现次数,但是肯定不能维护所有质数,所以使用根号分治(大质数-小质数Trick),对于“小的”质数开桶直接维护,对于“大的”质数离散化后单独处理。

实现上,我们以 \(10^3\) 为界,先筛出所有小质数(即小于 \(10^3\) 的),然后把所有数的大质数用泼辣肉干掉。为什么以 \(10^3\) 为界呢?一是因为 \(10^3\) 以内只有 \(168\) 个质数,空间全然能接受,二是因为 \(1001^3>10^9\),也就是说在这个阈值下一个数最多含有两个大质数,我们泼辣肉可以跑得很快。

这样这题就做完了。

代码实现

注意本题 \(a_i\le 10^9\),所以Miller-Rabin只用选取 \(2,7,61\) 三个底数即可。

#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=1e5+5,MaxK=1e3+5,CntP=170;
int N,M,klim=1e3,pcnt,A[MaxN],spri[CntP],sum[MaxN][CntP];
namespace omathe{
    const int mrps[3]={2,7,61};
    void polarosi(int n,vector<int> &vec){
        while(n!=1){
            if(milrab(n)){vec.push_back(n);return;}
            int x=polaros(n);n/=x,vec.push_back(x);
        }
    }
    int isp[MaxN];
    void erasieve(int n){
        fill(isp+2,isp+n+1,1);
        for(int i=2;i<=n;i++){
            if(!isp[i])continue;
            isp[i]=++pcnt,spri[isp[i]]=i;
            for(int j=i<<1;j<=n;j+=i)isp[j]=0;
        }
    }
    int inv[MaxN<<1];const int Mod=M192;
    void premwork(int n){inv[1]=1;for(int i=2;i<=n;i++)inv[i]=(Mod-Mod/i)*1ll*inv[Mod%i]%Mod;}
};
using namespace omathe;
vector<int> tmp,bpri;lolo ans[MaxN];
int B[MaxN][3],bcnt[MaxN],Nr,bel[MaxN];
struct quer{int l,r,id;}Q[MaxN];
bool cmp(quer a,quer b){return bel[a.l]==bel[b.l]?(bel[a.l]&1?a.r<b.r:a.r>b.r):a.l<b.l;}
int tot[MaxN<<1];
void mocadd(lolo &csum,int id){
    for(int i=1;i<=bcnt[id];i++){
        csum=csum*inv[tot[B[id][i]]]%Mod*(tot[B[id][i]]+1)%Mod,tot[B[id][i]]++;
    }
}
void mocdel(lolo &csum,int id){
    for(int i=1;i<=bcnt[id];i++){
        csum=csum*inv[tot[B[id][i]]]%Mod*(tot[B[id][i]]-1)%Mod,tot[B[id][i]]--;
    }
}
int main(){
    readis(N,M);erasieve(klim);Nr=sqrt(N);
    premwork(N<<1);fill(tot,tot+(N<<1)+1,1);
    for(int i=1;i<=N;i++){
        readi(A[i]),bel[i]=i/Nr+1;
        memcpy(sum[i],sum[i-1],sizeof(sum[i]));
        if(A[i]<=klim&&isp[A[i]]){sum[i][isp[A[i]]]++;continue;}
        for(int j=1;j<=pcnt&&spri[j]<=A[i];j++){
            while(!(A[i]%spri[j]))sum[i][j]++,A[i]/=spri[j];
        }
        if(A[i]==1)continue;
        tmp.clear(),polarosi(A[i],tmp);
        for(int x : tmp)B[i][++bcnt[i]]=x,bpri.push_back(x);
    }
    sort(bpri.begin(),bpri.end());
    bpri.erase(unique(bpri.begin(),bpri.end()),bpri.end());
    for(int i=1;i<=N;i++)for(int j=1;j<=bcnt[i];j++)B[i][j]=lwberi(bpri,B[i][j])+1;
    for(int i=1;i<=M;i++)readis(Q[i].l,Q[i].r),Q[i].id=i;
    sort(Q+1,Q+M+1,cmp);lolo csum=1;
    for(int i=1,cl=1,cr=0;i<=M;i++){
        while(cl>Q[i].l)mocadd(csum,--cl);
        while(cr<Q[i].r)mocadd(csum,++cr);
        while(cl<Q[i].l)mocdel(csum,cl++);
        while(cr>Q[i].r)mocdel(csum,cr--);
        lolo &cans=ans[Q[i].id];cans=csum;
        for(int j=1;j<=pcnt;j++)(cans*=(sum[cr][j]-sum[cl-1][j]+1))%=M192;
    }
    for(int i=1;i<=M;i++)writil(ans[i]);
    return 0;
}
posted @ 2025-05-14 20:02  矞龙OrinLoong  阅读(8)  评论(0)    收藏  举报