然后对于trunc(N/D)只有根号n个解,跳就完了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
#define ll long long
const int MAXN=55000;
bool vis[60000]={0};
ll prim[60000]={0};
ll cnt=0;
ll mu[60000]={0};//莫比乌斯函数
ll sum_mu[60000]={0};//莫比乌斯函数的前缀和
ll sum_f[60000]={0};//约数的前缀和
ll e[60000]={0};//当前最大此项质因数的系数
ll f[60000]={0};//约束和
void prime_pre(){
mu[1]=e[1]=f[1]=1;
for(ll i=2;i<=MAXN;i++){
if(!vis[i]){
cnt++;
prim[cnt]=i;
f[i]=2;
mu[i]=-1;
e[i]=1;
}
for(ll j=1;j<=cnt&&prim[j]*i<=MAXN;j++){
vis[prim[j]*i]=1;
if(i%prim[j]==0){
f[i*prim[j]]=f[i]/(e[i]+1)*(e[i]+2);
e[i*prim[j]]=e[i]+1;
break;
}
mu[i*prim[j]]=-mu[i];
f[i*prim[j]]=f[i]*f[prim[j]];
e[i*prim[j]]=1;
}
}
for(ll i=1;i<=MAXN;i++){
sum_mu[i]=sum_mu[i-1]+mu[i];
sum_f[i]=sum_f[i-1]+f[i];
}
}
int main(){
ll T;
scanf("%lld",&T);
prime_pre();
while(T--){
ll n,m;
scanf("%lld%lld",&n,&m);
if(n>m){
swap(n,m);
}
ll ans=0;
for(ll i=1,nxt;i<=n;i=nxt+1){
nxt=min(n/(n/i),m/(m/i));
ans+=(sum_mu[nxt]-sum_mu[i-1])*sum_f[n/i]*sum_f[m/i];
}
printf("%lld\n",ans);
}
}
本文深入探讨了一种高效的算法,用于求解两个数N和M的所有约数组合的乘积之和。通过预处理质数、莫比乌斯函数和约数的前缀和,该算法能在短时间内解决复杂问题,特别适用于竞赛编程和大规模数据处理。

被折叠的 条评论
为什么被折叠?



