洛谷 P5071 - [Ynoi2015] 此时此刻的光辉(莫队)
一道其实算得上常规的题,写这篇题解是为了总结一些数论中轻微(?)优化复杂度的技巧。
首先感性理解可以发现该问题强于区间数颜色问题,无法用常用的 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;
}
原文地址:https://www.cnblogs.com/ET2006/p/luogu-P5071.html
- SQL Server常用命令(平时不用别忘了)
- Spark详解06容错机制Cache 和 Checkpoint Cache 和 Checkpoint
- SQL Server 学习笔记
- Collaborative Filtering(协同过滤)算法详解
- 【Hadoop】三句话告诉你 mapreduce 中MAP进程的数量怎么控制?
- Spark系列课程-00xxSpark RDD持久化
- RDD持久化
- P02_Hadoop CDH 5.3.6集群搭建
- P01_Spark开发测试运行环境安装Spark开发测试运行环境安装
- spark2.x依赖包POM
- P03_Hive 安装
- P06_flume-ng-1.5.0-cdh5.3.6安装
- P04_zookeeper-cdh5集群搭建
- P05_kafka_2.9.2-0.8.1集群搭建
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- VCS与Verdi的联合仿真
- ADC数据接入到AXI-Steam Interface
- Java面试必问:ThreadLocal终极篇 淦!
- BERT文本摘要
- 【NPM库】- 0x01
- 基于分类任务的信号(EEG)处理--代码分步解析
- 文件操作——举例
- flink之udf执行流程分析篇
- VBA调用外部对象02:FileSystemObject——操作文本文件
- 打卡群刷题总结0723——组合
- VBA根据单元格底色统计个数
- 打卡群刷题总结0724——子集
- 打卡群刷题总结0726——删除排序数组中的重复项 II
- VBA调用外部对象02:FileSystemObject——OpenTextFile参数
- 使用HTTP 404-File Not Found的C2