原题链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3994
约数个数和
Description
设d(x)为x的约数个数,给定N、M,求 ∑ni=1∑mj=1d(ij) ∑ i = 1 n ∑ j = 1 m d ( i j )
Input
输入文件包含多组测试数据。
第一行,一个整数T,表示测试数据的组数。
接下来的T行,每行两个整数N、M。
Output
T行,每行一个整数,表示你所求的答案。
Sample Input
2
7 4
5 6
Sample Output
110
121
HINT
1<=N, M<=50000
1<=T<=50000
题解
初始式子:
首先,有这么一个结论( 证明):
这样,原来的式子就变成了:
我们再将
[gcd(x,y)=1]
[
g
c
d
(
x
,
y
)
=
1
]
加以替换(证明)
我们考虑枚举
d
d
,因此要满足
[d|gcd(x,y)]
[
d
|
g
c
d
(
x
,
y
)
]
:
我们考虑直接枚举
d
d
:
我们再从枚举
i,j
i
,
j
变为枚举
x,y
x
,
y
,那么满足
x|i,y|j
x
|
i
,
y
|
j
的
x,y
x
,
y
就分别有
⌊nx⌋,⌊my⌋
⌊
n
x
⌋
,
⌊
m
y
⌋
个,代入:
进一步的,
[d|gcd(x,y)]
[
d
|
g
c
d
(
x
,
y
)
]
这个判定条件十分碍眼,我们需要消去它。于是,我们不再单纯枚举
x,y
x
,
y
,直接枚举
d
d
的倍数:
由于,
⌊ndx⌋
⌊
n
d
x
⌋
只与
n,d,x
n
,
d
,
x
有关,所以可以提前:
考虑这个形状:
我们可以发现,
⌊ni⌋
⌊
n
i
⌋
相当于统计
1∼n
1
∼
n
中,能被
i
i
整除的数有多少,那么就是统计了
1∼n
1
∼
n
中,所有数的因数有多少个,即
1∼n
1
∼
n
的因数个数和:
注: σ0(x) σ 0 ( x ) 函数与 d(x) d ( x ) 函数意义相同,都表示约数个数,这里为了不与第一个 Σ Σ 中的 d d 混淆,使用
那么,最终形态就变成了:
σ0(x) σ 0 ( x ) 为积性函数,资瓷线筛,因此我们可以预处理前缀和,再利用下底分块,我们便能 O(n−−√) O ( n ) 回答询问。
代码
#include<bits/stdc++.h>
#define R register int
using namespace std;
const int M=5e4+5,N=5e4;
int miu[M],d[M],p[M],num[M],T;
bool check[M];
void get()
{
R i,j,t;
miu[1]=d[1]=check[1]=1;
for(i=2;i<=N;++i)
{
if(!check[i])miu[i]=-1,d[i]=2,num[i]=1,p[++p[0]]=i;
for(j=1;j<=p[0];++j)
{
t=i*p[j];if(t>N)break;
check[t]=1;
if(i%p[j]==0){miu[t]=0;num[t]=num[i]+1;d[t]=d[i]/(num[i]+1)*(num[i]+2);break;}
miu[t]=-miu[i],num[t]=1,d[t]=d[i]<<1;
}
d[i]+=d[i-1],miu[i]+=miu[i-1];
}
}
long long ans;
void f(int n,int m)
{
R l,r;ans=0;
if(n>m)swap(n,m);
for(l=1;l<=n;l=r+1)r=min(n/(n/l),m/(m/l)),ans+=1ll*(miu[r]-miu[l-1])*d[n/l]*d[m/l];
}
void in(){get();scanf("%d",&T);}
void ac()
{
R a,b,i;
for(i=1;i<=T;++i)
scanf("%d%d",&a,&b),f(a,b),printf("%lld\n",ans);
}
int main()
{
in();ac();
return 0;
}