【数论】[SDOI2015]约数个数和
传送门:
https://www.luogu.com.cn/problem/P3327
https://www.acwing.com/problem/content/1360/
莫比乌斯反演 + 整除分块
分析
首先,我们给出一个结论:
证明:
设 的分解式为 ,类似地,
对于质数 , 对应的因数个数为
而对于右式, 如果想要产生贡献,那么只可能是: 不同时存在因数 ,注意到对应的贡献数即为
因此,由乘法原理,所求证式成立。
为了防止混淆,我们将题面中的 记为
由上述结论,题目的式子转化为:
莫比乌斯反演:若 ,则有
于是我们设 ,对应的
下面对 进行变换:
设 ,进而有
记 , 可用整除分块处理。
由莫比乌斯反演, ,我们只需求
下面对 进行变换:
由整除分块知, 取值最多为 块,而对于每一块,可以用前缀和 处理出对应的 值,因此整体的复杂度为
细节见代码:
#include<bits/stdc++.h>
using namespace std;
const int S=50050;
int primes[S], cnt;
bool vis[S];
int mu[S], sum[S];
int h[S];
int g(int b, int l){
return b/(b/l);
}
void init(){
// init sum[]
mu[1]=1;
for(int i=2; i<S; i++){
if(!vis[i]) primes[cnt++]=i, mu[i]=-1;
for(int j=0; i*primes[j]<S; j++){
vis[i*primes[j]]=true;
if(i%primes[j]==0) break;
mu[i*primes[j]]=-mu[i];
}
}
for(int i=1; i<S; i++) sum[i]=sum[i-1]+mu[i];
// init h[]
for(int x=1; x<S; x++){
int &v=h[x];
for(int l=1, r; l<=x; l=r+1){
r=min(x, g(x, l));
v+=x/l*(r-l+1);
}
}
}
int solve(int N, int M){
int res=0;
int n=min(N, M);
for(int l=1, r; l<=n; l=r+1){
r=min(n, min(g(N, l), g(M, l)));
res+=(sum[r]-sum[l-1])*h[N/l]*h[M/l];
}
return res;
}
int main(){
int T; cin>>T;
init();
while(T--){
int N, M; cin>>N>>M;
cout<<solve(N, M)<<endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】