Luogu P1390 公约数的和
gate
求:
n∑i=1m∑j=1gcd(i,j)
设gcd(i,j)=k,枚举k
n∑k=1kn∑i=1m∑j=1[gcd(i,j)=k]
同时除以k
n∑k=1k⌊nk⌋∑i=1⌊mk⌋∑j=1[gcd(i,j)=1]
根据
\begin{array} \ \because \sum\limits_{d∣n}\mu(d)=[n=1] \\ \therefore \sum\limits_{d∣gcd(i,j)}μ(d) = [gcd(i,j)=1] \end{array}
把[gcd(i,j)=1]替换掉
\sum\limits_{k=1}^n k \sum\limits_{i=1}^{\lfloor \frac{n}{k}\rfloor}\sum\limits_{j=1}^{\lfloor \frac{m}{k}\rfloor} \sum\limits_{d∣n}\mu(d)
将d提前,同时把i,j除以d
\sum\limits_{k=1}^n k\sum\limits_{d=1}^{\lfloor \frac{n}{k}\rfloor}\sum\limits_{i=1}^{\lfloor \frac{n}{kd}\rfloor}\sum\limits_{j=1}^{\lfloor \frac{m}{kd}\rfloor}\mu(d)
整除分块
\sum\limits_{k=1}^n k\sum\limits_{d=1}^{\lfloor \frac{n}{k}\rfloor}\mu(d)\lfloor \frac{n}{kd}\rfloor\lfloor \frac{m}{kd}\rfloor
设T=kd
\sum\limits_{k=1}^n k\sum\limits_{d=1}^{\lfloor \frac{n}{k}\rfloor}\mu(d)\lfloor \frac{n}{T}\rfloor\lfloor \frac{m}{T}\rfloor
把d换成T
\sum\limits_{T=1}^n\sum\limits_{k|T} k\mu(\frac{T}{k})\lfloor \frac{n}{T}\rfloor\lfloor \frac{m}{T}\rfloor
k也就是id(k),可以写成
\sum\limits_{T=1}^n\sum\limits_{k|T} id(k)\mu(\frac{T}{k})\lfloor \frac{n}{T}\rfloor\lfloor \frac{m}{T}\rfloor
因为k*\frac{T}{k} = T,所以在枚举T时,k和\frac{T}{k}可以看成相同的元素,只是顺序相反
\begin{array} \ \because id*\mu=\varphi \\ \therefore \sum\limits_{k|T}id(k)\mu(\frac{T}{k}) = \sum\limits_{k|T}\varphi(k) \end{array}
\because \varphi是积性函数
\therefore \sum\limits_{k|T}\varphi(k) = \varphi(T)
即原式可以转化为
\sum\limits_{T=1}^n\varphi(T)\lfloor \frac{n}{T}\rfloor\lfloor \frac{m}{T}\rfloor
莫比乌斯反演的部分到此结束了,但注意,题目要求的是[1,n]中每任意两个不同的数的gcd之和,
而上述做法多加了gcd(i,i),且重复计算了gcd(i,j)和gcd(j,i)
所以我们要把多余的部分减去,最终答案即 (Ans-\sum\limits_{i=1}^ni)/2
也就是等差数列,可以写成(Ans-(1+n)*n/2)/2
代码如下
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define MogeKo qwq
using namespace std;
const int maxn = 2e6+5;
long long n,p[maxn];
void get_phi(long long n) {
for(long long i = 1; i <= n; i++)
p[i] = i;
for(long long i = 2; i <= n; i++)
if(p[i] == i)
for(long long j = i; j <= n; j += i)
p[j] = p[j]/i*(i-1);
for(long long i = 1; i <= n; i++)
p[i] += p[i-1];
}
long long calc(long long n,long long m) {
long long ans = 0;
long long r = 0;
for(long long i = 1; i <= n; i = r+1) {
r = min(n/(n/i),m/(m/i));
ans += (p[r]-p[i-1]) * (n/i) * (m/i);
}
return ans;
}
int main() {
scanf("%lld",&n);
get_phi(n);
printf("%lld",(calc(n,n)-(1+n)*n/2)/2);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步