[SDOI2015]约数个数和
iv.[SDOI2015]约数个数和
完蛋了,我们前几题里面都有,但是这道题没有,怎么办呢?
引理:
换句话说,两个数积的因数个数,等于的所有因数与的所有因数中互质的对数。
简单证明(感谢suncongbo巨佬的讲解):
显然各质因数之间相互独立(最后是个数乘在一起,只要每一项都相等,乘积也就相等),我们不如只考虑一个质因数。设它在中的次数是,在中的次数是。那么,在乘积中,次数就是。
考虑仅一项为贡献了多少因数。显然,是个,次数从一直到。
那么为等式右侧贡献了多少呢?当中不取任何时,中可以取到个,共种;当中不取任何时,中可以取到个,共种;除此之外,还有一种和都不选的,共种。综上,为等式右侧它也贡献了。
因为对于每一个单独的,等式左右的贡献相等;所以综合起来考虑,等式左右贡献的积也相等。
证毕。
然后我们看一看套上这个东西后我们要求什么:
。
这个时候,我们就应该想想有没有可能调换枚举顺序。
优先枚举和,则对于每个,有个这样的,满足并且。对于每个,则有个这样的。
因此有。
老套路,设,。
反演一下,得。
我们要求的是,。
我们看一下是什么。
有
发现这个可以是任何的倍数。因此有
我们将除出来,有
我们令一个,这个东西可以在时间内通过整除分块写出来。
则。
又有,这东西也可以整除分块,因为里面有一个可以整除分块的和一个可以求前缀和的。
然后就可以了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int T,n,m,mu[50100],pri[50100],sum[50100],res;
void getmu(int N){
mu[1]=1;
for(int i=2;i<=N;i++){
if(!pri[i])pri[++pri[0]]=i,mu[i]=-1;
for(int j=1;j<=pri[0]&&i*pri[j]<=N;j++){
pri[i*pri[j]]=true;
if(!(i%pri[j]))break;
mu[i*pri[j]]=-mu[i];
}
}
for(int i=1;i<=N;i++)mu[i]+=mu[i-1];
}
void getsum(int N){
for(int i=1;i<=N;i++)for(int l=1,r;l<=i;l=r+1)r=i/(i/l),sum[i]+=(r-l+1)*(i/l);
}
signed main(){
scanf("%lld",&T),getmu(50000),getsum(50000);
while(T--){
scanf("%lld%lld",&n,&m);
if(n>m)swap(n,m);
res=0;
for(int l=1,r;l<=n;l=r+1)r=min(n/(n/l),m/(m/l)),res+=(mu[r]-mu[l-1])*sum[n/l]*sum[m/l];
printf("%lld\n",res);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?