LGP5071 [Ynoi 2015-E] 此时此刻的光辉 学习笔记
LGP5071 [Ynoi 2015-E] 此时此刻的光辉 学习笔记
前言
敬我的第一场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;
}
浙公网安备 33010602011771号