题解:[SDOI2015] 约数个数和

洛谷P3327

Posted by TH911 on August 18, 2025

题目传送门

题意分析

不妨令 $n\leq m$。

首先,答案为:

\[\sum_{i=1}^n\sum_{j=1}^md(ij)\]

这个 $d(ij)$ 表示 $ij$ 的约数个数,很不好处理。

因此可以考虑 $d(ij)$ 能否化简,有:

\[d(ij)=\sum_{x\mid i}\sum_{y\mid i}[x\perp y]\]

证明参见此处

因此可以进行推导。记答案为 $\textit{ans}$

\(\begin{aligned} \textit{ans}&=\sum_{i=1}^n\sum_{j=1}^m\sum_{x\mid i}\sum_{y\mid i}[x\perp y]\\ &=\sum_{x=1}^n\sum_{y=1}^m[x\perp y]\sum_{i=1}^{\left\lfloor\frac nx\right\rfloor}\sum_{j=1}^{\left\lfloor\frac my\right\rfloor}1\\ &=\sum_{x=1}^n\sum_{y=1}^m[x\perp y]\left\lfloor\frac nx\right\rfloor\left\lfloor\frac my\right\rfloor\\ &=\sum_{x=1}^n\sum_{y=1}^m\sum_{t\mid\gcd(x,y)}\mu(t)\left\lfloor\frac nx\right\rfloor\left\lfloor\frac my\right\rfloor\\ &=\sum_{t=1}^n\mu(t)\sum_{x=1}^{\left\lfloor\frac nt\right\rfloor}\sum_{y=1}^{\left\lfloor\frac mt\right\rfloor}\left\lfloor\frac n{xt}\right\rfloor\left\lfloor\frac m{yt}\right\rfloor\\ &=\sum_{t=1}^n\mu(t)\left(\sum_{x=1}^{\left\lfloor\frac nt\right\rfloor}\left\lfloor\frac n{xt}\right\rfloor\right)\left(\sum_{y=1}^{\left\lfloor\frac mt\right\rfloor}\left\lfloor\frac m{yt}\right\rfloor\right) \end{aligned}\) 预处理 $\displaystyle s_i=\sum_{x=1}^i\left\lfloor\frac ni\right\rfloor$ 即可利用数论分块 $\mathcal O(\sqrt n)$ 计算。

AC 代码

时间复杂度:$\mathcal O(T\sqrt n)$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
typedef long long ll;
constexpr const int N=50000;
int mu[N+1];
ll s[N+1];
void pre(){
	static int vis[N+1],prime[N+1],size;
	mu[1]=1; 
	for(int i=2;i<=N;i++){
		if(!vis[i]){
			vis[i]=i;
			prime[++size]=i;
			mu[i]=-1;
		}
		for(int j=1;j<=size&&i*prime[j]<=N;j++){
			vis[i*prime[j]]=prime[j];
			if(i%prime[j]==0){
				break;
			}
			mu[i*prime[j]]=-mu[i];
		}
	}
	for(int i=1;i<=N;i++){
		mu[i]+=mu[i-1];
	}
	for(int i=1;i<=N;i++){
		for(int l=1,r;l<=i;l=r+1){
			int ti=i/l;
			r=i/ti;
			s[i]+=(r-l+1ll)*ti;
		}
	}
}
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	pre();
	int T;
	cin>>T;
	while(T--){
		int n,m;
		cin>>n>>m;
		if(m>n){
			swap(n,m);
		}
		ll ans=0;
		for(int l=1,r;l<=m;l=r+1){
			int tn=n/l,tm=m/l;
			r=min(n/tn,m/tm);
			ans+=(mu[r]-mu[l-1])*s[tn]*s[tm];
		}
		cout<<ans<<'\n';
	}
	
	cout.flush();
	 
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}