设d(x)为x的约数个数,给定N、M,求 ∑i=1N∑j=1Md(ij)\sumN_{i=1}\sumM_{j=1}d(ij)∑i=1N∑j=1Md(ij)
输入格式
输入文件包含多组测试数据。第一行,一个整数T,表示测试数据的组数。接下来的T行,每行两个整数N、M。
输出格式
T行,每行一个整数,表示你所求的答案。
输入输出样例
输入 #1
2
7 4
5 6
输出 #1
110
121
说明/提示
1<=N, M<=50000
1<=T<=50000
求 ∑ i = 1 N ∑ j = 1 M d ( i j ) 求\sum_{i=1}^N\sum_{j=1}^M{d(ij)} 求i=1∑Nj=1∑Md(ij)
对于d函数有个性质,在最上面题目链接页面中的解题报告中有它的证明,不过能力不够,不太理解,先记着吧
d ( i j ) = ∑ x ∣ i ∑ y ∣ j [ g c d ( x , y ) = 1 ] d(ij)=\sum_{x|i}\sum_{y|j}{[gcd(x,y)=1]} d(ij)=x∣i∑y∣j∑[gcd(x,y)=1]
注:[gcd(x,y)=1]表示gcd(x,y)等于1时值为1,其余情况为0
那么所求为
∑ i = 1 N ∑ j = 1 M ∑ x ∣ i ∑ y ∣ j [ g c d ( x , y ) = 1 ] \sum_{i=1}^N\sum_{j=1}^M{\sum_{x|i}\sum_{y|j}{[gcd(x,y)=1]}} i=1∑Nj=1∑Mx∣i∑y∣j∑[gcd(x,y)=1]
上式中,假如以x,y为自变量,i和j满足分别是x,y的倍数,对应的个数分别为 N x , M y \frac{N}{x},\frac{M}{y} xN,yM(注:像这种除法的,若没有特别说明,都表示向下取整),由此改变枚举顺序得
∑ x = 1 N ∑ y = 1 M [ g c d ( x , y ) = 1 ] ⋅ N x ⋅ M y \sum_{x=1}^N\sum_{y=1}^M{[gcd(x,y)=1]\cdot \frac{N}{x}\cdot \frac{M}{y} } x=1∑Ny=1∑M[gcd(x,y)=1]⋅xN⋅yM
定义f(n)函数,和g(n)函数:
f ( n ) : = ∑ x = 1 N ∑ y = 1 M [ g c d ( x , y ) = n ] ⋅ N x ⋅ M y g ( n ) : = ∑ n ∣ d f ( d ) = ∑ x = 1 N ∑ y = 1 M [ n ∣ g c d ( x , y ) ] ⋅ N x ⋅ M y f(n) :=\sum_{x=1}^N\sum_{y=1}^M{[gcd(x,y)=n]\cdot \frac{N}{x}\cdot \frac{M}{y} }\\ g(n):=\sum_{n|d}{f(d)}\\ =\sum_{x=1}^N\sum_{y=1}^M{[n|gcd(x,y)]\cdot \frac{N}{x}\cdot \frac{M}{y} } f(n):=x=1∑Ny=1∑M[gcd(x,y)=n]⋅xN⋅yMg(n):=n∣d∑f(d)=x=1∑Ny=1∑M[n∣gcd(x,y)]⋅xN⋅yM
题目所求为 f ( 1 ) f(1) f(1)
对g(n)进一步化简,由于 n ∣ g c d ( x , y ) n|gcd(x,y) n∣gcd(x,y),所以令 x = a ⋅ n , y = b ⋅ n x=a\cdot n,y=b\cdot n x=a⋅n,y=b⋅n,代入得
g ( n ) = ∑ a ⋅ n = 1 N ∑ b ⋅ n = 1 M [ n ∣ g c d ( a ⋅ n , b ⋅ n ) ] ⋅ N a ⋅ n ⋅ M b ⋅ n = ∑ a = 1 N n ∑ b = 1 M n [ 1 ∣ g c d ( a , b ) ] ⋅ N a ⋅ n ⋅ M b ⋅ n = ∑ a = 1 N n ∑ b = 1 M n N a ⋅ n ⋅ M b ⋅ n g(n)=\sum_{a\cdot n=1}^N\sum_{b\cdot n=1}^M{[n|gcd(a\cdot n,b\cdot n)]\cdot \frac{N}{a\cdot n}\cdot \frac{M}{b\cdot n} }\\ =\sum_{a =1}^{\frac{N}{n}}\sum_{b=1}^{\frac{M}{n}}{[1|gcd(a,b)]\cdot \frac{N}{a\cdot n}\cdot \frac{M}{b\cdot n} }\\ =\sum_{a =1}^{\frac{N}{n}}\sum_{b=1}^{\frac{M}{n}}{\frac{N}{a\cdot n}\cdot \frac{M}{b\cdot n} } g(n)=a⋅n=1∑Nb⋅n=1∑M[n∣gcd(a⋅n,b⋅n)]⋅a⋅nN⋅b⋅nM=a=1∑nNb=1∑nM[1∣gcd(a,b)]⋅a⋅nN⋅b⋅nM=a=1∑nNb=1∑nMa⋅nN⋅b⋅nM
反演得:
f ( n ) = ∑ n ∣ d μ ( d n ) g ( d ) f(n)=\sum_{n|d}{μ(\frac{d}{n})g(d)} f(n)=n∣d∑μ(nd)g(d)
n = 1 n=1 n=1代入得
f ( 1 ) = ∑ 1 ∣ d μ ( d ) g ( d ) = ∑ d = 1 m i n ( N , M ) μ ( d ) g ( d ) = ∑ d = 1 m i n ( N , M ) μ ( d ) g ( d ) f(1)=\sum_{1|d}{μ(d)g(d)}\\ =\sum_{d=1}^{min(N,M)}{μ(d)g(d)}\\ =\sum_{d=1}^{min(N,M)}{μ(d)g(d)} f(1)=1∣d∑μ(d)g(d)=d=1∑min(N,M)μ(d)g(d)=d=1∑min(N,M)μ(d)g(d)
定义s(n)函数
s ( n ) : = ∑ i = 1 n n i s(n):=\sum_{i=1}^{n}{\frac{n}{i}} s(n):=i=1∑nin
则有
g ( n ) = ∑ a = 1 N n ∑ b = 1 M n N a ⋅ n ⋅ M b ⋅ n = ∑ a = 1 N n N a ⋅ n ∑ b = 1 M n M b ⋅ n g(n)=\sum_{a =1}^{\frac{N}{n}}\sum_{b=1}^{\frac{M}{n}}{\frac{N}{a\cdot n}\cdot \frac{M}{b\cdot n} }\\ =\sum_{a =1}^{\frac{N}{n}}{{\frac{N}{a\cdot n}\sum_{b=1}^{\frac{M}{n}} \frac{M}{b\cdot n} }} g(n)=a=1∑nNb=1∑nMa⋅nN⋅b⋅nM=a=1∑nNa⋅nNb=1∑nMb⋅nM
由于a,b间没有关联,故
g ( n ) = s ( N n ) ⋅ s ( M n ) g(n)=s(\frac{N}{n})\cdot s(\frac{M}{n}) g(n)=s(nN)⋅s(nM)
所以
f ( 1 ) = ∑ d = 1 m i n ( N , M ) μ ( d ) g ( d ) = ∑ d = 1 m i n ( N , M ) μ ( d ) ⋅ s ( N d ) ⋅ s ( M d ) f(1)=\sum_{d=1}^{min(N,M)}{μ(d)g(d)}=\sum_{d=1}^{min(N,M)}{μ(d)\cdot s(\frac{N}{d})\cdot s(\frac{M}{d})} f(1)=d=1∑min(N,M)μ(d)g(d)=d=1∑min(N,M)μ(d)⋅s(dN)⋅s(dM)
对于s函数,分块求,得预处理,否则会超时。对于μ,预处理求前缀和,求μ*s*s的时候也得分块求
#include
using namespace std;
const int N=5e4+5;
#define ll long long
int prime[N+1];
int mob[N+1];
ll sum[N+1];
ll s[N+1];
void Mobius()
{
memset(prime,0,sizeof(prime));
mob[1]=1;
sum[1]=1;
for(int i=2;i<=N;i++)
{
if(!prime[i])
{
prime[++prime[0]]=i;
mob[i]=-1;
}
for(int j=1;j<=prime[0] && i*prime[j]<=N;j++)
{
prime[i*prime[j]]=1;
if(i%prime[j]==0)
{
mob[i*prime[j]]=0;
break;
}
mob[i*prime[j]]=-mob[i];
}
sum[i]=sum[i-1]+mob[i];
}
}
void get_s()
{
/* ll ans=0;
for(int l=1, r;l<=n;l=r+1)
{
r=n/(n/l);
ans += 1LL*(r-l+1)*(n/l);
}
return ans; */
for(int x=1;x<=N;x++)
{
s[x]=0;
for(int l=1,r; l<=x;l=r+1)
{
r=x/(x/l);
s[x] += 1LL*(r-l+1)*(x/l);
}
}
}
ll solve(int n,int m)
{
ll ans=0;
int lim=min(n,m);
for(int l=1,r ; l<=lim; l=r+1)
{
r=min( n/(n/l),m/(m/l) );
ans += 1LL*(sum[r]-sum[l-1])*s[n/l]*s[m/l];
}
return ans;
}
int main()
{
Mobius();
get_s();
int T, n, m;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
printf("%lld\n",solve(n,m));
}
return 0;
}