洛谷题面传送门

一道其实算得上常规的题,写这篇题解是为了总结一些数论中轻微(?)优化复杂度的技巧。

首先感性理解可以发现该问题强于区间数颜色问题,无法用常用的 log 数据结构维护,因此考虑分块/莫队。显然这题莫队比较好些对吧?显然我们要对每个质因子计算一遍它在 \([l,r]\) 中的出现次数对吧?涉及质因子就要分解质因数对吧?莫队时候新添一个元素很明显就要枚举它的每个质因子,然后计算新添的贡献对吧?线性预处理乘法逆元以后,复杂度就变成了 \(n\sqrt{a_i}+(n+q)\sqrt{n}\omega(a_i)\),其中左边的分解质因数的复杂度,右边是莫队的复杂度,对吧?恭喜你,你完美地获得了 TLE 的好成绩。

考虑优化。加号左右两部分显然都不可行,都要进行优化。左边一部分相对比较容易:考虑预处理出 \([1,\sqrt{a_i}]\) 中所有质因子,这样每次分解不必 \([1,\sqrt{a_i}]\) 跑一遍,只用跑其中 \(\mathcal O(\dfrac{\sqrt{a_i}}{\ln\sqrt{a_i}})\) 个质因子即可,这样左边的复杂度就变成了 \(\dfrac{\sqrt{a_i}}{\ln\sqrt{a_i}}·n\)。再考虑右边,注意到在每个数所有不同质因子中,大部分都比较小,因此考虑用类似于根号分治的方法,我们预处理 \([1,\sqrt[3]{a_i}]\) 中所有质因子,对于 \([1,\sqrt[3]{a_i}]\) 中质因子的贡献,我们直接前缀和扫一遍即可计算,复杂度 \((n+q)\pi(\sqrt[3]{a_i})\),对于 \(>\sqrt[3]{a_i}\) 的质因子的贡献就按照上面的方法进行莫队。注意到一个数最多有 \(2\) 个 \(>\sqrt[3]{a_i}\) 的因子,因此莫队的 \(\omega\) 就变成了常数,总复杂度也进而变为 \(\dfrac{\sqrt{a_i}}{\ln\sqrt{a_i}}·n+(n+q)\pi(\sqrt[3]{a_i})+(n+q)\sqrt{n}\)。

const int MAXN=1e5;
const int MAXV=31630;
const int LIM=1000;
const int PI_LIM=220;
const int MAXX=1e6;
const int BLK=316;
int n,qu,a[MAXN+5];
int pr[MAXV/6+5],prcnt=0,vis[MAXV+5];
void sieve(int n){
for(int i=2;i<=n;i++){
if(!vis[i]) pr[++prcnt]=i;
for(int j=1;j<=prcnt&&pr[j]*i<=n;j++){
vis[pr[j]*i]=1;if(i%pr[j]==0) break;
}
}
}
int c[MAXN+5][3],cc[MAXN+5];
int sum[MAXN+5][PI_LIM+5],inv[MAXX+5];
int res[MAXN+5],bel[MAXN+5],L[BLK+5],R[BLK+5],blk_sz,blk_cnt;
int key[MAXN*2+5],uni[MAXN*2+5],ccnt=0,num=0;
struct qry{
int l,r,id;
bool operator <(const qry &rhs){
if(bel[l]^bel[rhs.l]) return bel[l]<bel[rhs.l];
else if(bel[l]&1) return r<rhs.r;
else return r>rhs.r;
}
} q[MAXN+5];
int cnt[MAXN*2+5],mul=1;
void ins(int x){
for(int i=1;i<=cc[x];i++){
mul=1ll*mul*inv[cnt[c[x][i]]+1]%MOD;
cnt[c[x][i]]++;
mul=1ll*mul*(cnt[c[x][i]]+1)%MOD;
}
}
void del(int x){
for(int i=1;i<=cc[x];i++){
mul=1ll*mul*inv[cnt[c[x][i]]+1]%MOD;
cnt[c[x][i]]--;
mul=1ll*mul*(cnt[c[x][i]]+1)%MOD;
}
}
int main(){
scanf("%d%d",&n,&qu);sieve(MAXV);
blk_sz=(int)sqrt(n);blk_cnt=(n-1)/blk_sz+1;
for(int i=1;i<=blk_cnt;i++){
L[i]=(i-1)*blk_sz+1;R[i]=min(i*blk_sz,n);
for(int j=L[i];j<=R[i];j++) bel[j]=i;
}
for(int i=(inv[0]=inv[1]=1)+1;i<=MAXX;i++) inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
int tmp=a[i];
for(int j=1;j<=prcnt;j++) if(tmp%pr[j]==0){
int cnt=0;
while(tmp%pr[j]==0) tmp/=pr[j],cnt++;
if(pr[j]<=LIM) sum[i][j]=cnt;
else{
c[i][++cc[i]]=pr[j];
if(cnt==2) c[i][++cc[i]]=pr[j];
}
} if(tmp>1) c[i][++cc[i]]=tmp;
for(int j=1;j<=cc[i];j++) key[++ccnt]=c[i][j];
} sort(key+1,key+ccnt+1);
for(int i=1;i<=n;i++) for(int j=1;j<=prcnt;j++){
if(pr[j]>LIM) break;sum[i][j]+=sum[i-1][j];
}
for(int i=1;i<=ccnt;i++) if(key[i]^key[i-1]) uni[++num]=key[i];
for(int i=1;i<=n;i++) for(int j=1;j<=cc[i];j++)
c[i][j]=lower_bound(uni+1,uni+num+1,c[i][j])-uni;
for(int i=1;i<=qu;i++){
scanf("%d%d",&q[i].l,&q[i].r);q[i].id=i;res[i]=1;
for(int j=1;j<=prcnt;j++){
if(pr[j]>LIM) break;
res[i]=1ll*res[i]*(sum[q[i].r][j]-sum[q[i].l-1][j]+1)%MOD;
}
} sort(q+1,q+qu+1);int cl=1,cr=0;
for(int i=1;i<=qu;i++){
while(cr<q[i].r) ins(++cr);
while(cl>q[i].l) ins(--cl);
while(cl<q[i].l) del(cl++);
while(cr>q[i].r) del(cr--);
res[q[i].id]=1ll*res[q[i].id]*mul%MOD;
}
for(int i=1;i<=qu;i++) printf("%d\n",res[i]);
return 0;
}

洛谷 P5071 - [Ynoi2015] 此时此刻的光辉(莫队)的更多相关文章

  1. Bzoj2120/洛谷P1903 数颜色(莫队)

    题面 Bzoj 洛谷 题解 考虑对操作离线后分块处理询问操作(莫队算法),将询问操作按照编号分块后左端点第一关键字,右端点第二关键字排序(分块大小为\(n^{\frac 23}\)),对于每一个询问操 ...

  2. 【题解】Luogu P5071 [Ynoi2015]此时此刻的光辉

    众所周知lxl是个毒瘤,Ynoi道道都是神仙题,题面好评 原题传送门 一看这题没有修改操作就知道这是莫队题(我也只会莫队) 我博客里对莫队的简单介绍 一个数N可以分解成\(p_1^{c_1}p_2^{ ...

  3. 洛谷P3901 数列找不同 [莫队]

    题目传送门 题目描述 现有数列 A_1,A_2,\cdots,A_NA1​,A2​,⋯,AN​ ,Q 个询问 (L_i,R_i)(Li​,Ri​) , A_{Li} ,A_{Li+1},\cdots, ...

  4. 洛谷P3245 [HNOI2016]大数 【莫队】

    题目 题解 除了\(5\)和\(2\) 后缀数字对\(P\)取模意义下,两个位置相减如果为\(0\),那么对应子串即为\(P\)的倍数 只用对区间种相同数个数\(x\)贡献\({x \choose 2 ...

  5. P5071 [Ynoi2015]此时此刻的光辉

    传送门 lxl大毒瘤 首先一个数的因子个数就是这个数的每个质因子的次数+1的积,然后考虑把每个数分解质因子,用莫队维护,然后我交上去就0分了 如果是上面那样的话,我们每一次移动指针的时间复杂度是O(这 ...

  6. 洛谷 P4887 -【模板】莫队二次离线(第十四分块(前体))(莫队二次离线)

    题面传送门 莫队二次离线 mol ban tea,大概是这道题让我第一次听说有这东西? 首先看到这类数数对的问题可以考虑莫队,记 \(S\) 为二进制下有 \(k\) 个 \(1\) 的数集,我们实时 ...

  7. 洛谷P3901 数列找不同(莫队水题)

    重温下手感,判断区间是否全是不同的数字有两种做法,一个长度为len的区间不同的数字,参见HH的项链,一种是区间众数,参见蒲公英,是水题没错了.明天搞数据库,然后继续自己的gre和训练计划 #inclu ...

  8. [Ynoi2015]此时此刻的光辉(莫队)

    一道神题...自己写出来以后被卡常了...荣获洛谷最差解... 思路还是比较好想,对于每个数 \(\sqrt{n}\) 分块,对于 \(\sqrt{n}\) 以内的数,我们可以直接求出来.对于 \(\ ...

  9. Luogu5071 [Ynoi2015]此时此刻的光辉 【莫队】

    题目链接:洛谷 这个跟上上个Ynoi题目是一样的套路,首先我们知道\(n=\prod p_i^{\alpha_i}\)时\(d(n)=\prod (\alpha_i+1)\). 首先对所有数分解质因数 ...

随机推荐

  1. JVM:内存结构

    JVM:内存结构 说明:这是看了 bilibili 上 黑马程序员 的课程 JVM完整教程 后做的笔记 内容 程序计数器 虚拟机栈 本地方法栈 堆 方法区 直接内存 1. 程序计数器 1.1 定义 P ...

  2. Scrum Meeting 16

    第16次例会报告 日期:2021年06月11日 会议主要内容概述: 最后一次例会 一.进度情况 我们采用日报的形式记录每个人的具体进度,链接Home · Wiki,如下记录仅为保证公开性: 组员 负责 ...

  3. 【技术博客】利用handler实现线程之间的消息传递

    [技术博客]利用handler实现线程之间的消息传递 一.handler简介 在Android Studio的开发中,经常需要启动多个线程.比如向远程发送请求时,必须新开一个子线程,否则会造成程序崩溃 ...

  4. BUAA SE | 提问回顾与个人总结

    项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 提问回顾与个人总结 我在这个课程的目标是 深入理解软件工程 这个作业在哪个具体方面帮助我实现目标 ...

  5. Golang通脉之并发初探

    并发是编程里面一个非常重要的概念,Go语言在语言层面天生支持并发. 并发与并行 并发:同一时间段内执行多个任务. 并行:同一时刻执行多个任务,有时间上的重叠. 进程.线程.协程 进程(Process) ...

  6. Machine learning(3-Linear Algebra Review )

    1.Matrices and vectors Matrix :Rectangular array of numbers a notation R3×3 Vector : An n×1 matrix t ...

  7. 2021NOI同步赛

    \(NOI\) 网上同步赛 明白了身为菜鸡的自己和普通人的差距 DAY1 \(T1\) 轻重边 [题目描述] 小 W 有一棵 \(n\) 个结点的树,树上的每一条边可能是轻边或者重边.接下来你需要对树 ...

  8. 用C++实现的数独解题程序 SudokuSolver 2.7 及实例分析

    引言:一个 bug 的发现 在 MobaXterm 上看到有内置的 Sudoku 游戏,于是拿 SudokuSolver 求解,随机出题,一上来是个 medium 级别的题: 073 000 060 ...

  9. cm0 逆向分析

    目录 cm0 逆向分析 前言 Strings工具复习 String工具使用说明 Strings工具解cm0题 cm0 逆向分析 前言 Emmmmm,我假装你看到这里已经学过了我的<恶意代码分析实 ...

  10. 百亿级小文件存储,JuiceFS 在自动驾驶行业的最佳实践

    自动驾驶是最近几年的热门领域,专注于自动驾驶技术的创业公司.新造车企业.传统车厂都在这个领域投入了大量的资源,推动着 L4.L5 级别自动驾驶体验能尽早进入我们的日常生活. 自动驾驶技术实现的核心环节 ...