公约数的和 / 最大公约数 / GCD SUM【欧拉函数】

>Link

luogu P1390

luogu P2398


>Description

给出 n n n,求 ∑ i = 1 n − 1 ∑ j = i + 1 n g c d ( i , j ) \sum_{i=1}^{n-1}\sum_{j=i+1}^{n}gcd(i,j) i=1n1j=i+1ngcd(i,j)
(GCD SUM的题面会略有不同,但是原理都是一样的,稍微改动就好了)


>解题思路

#关于欧拉函数
φ ( n ) \varphi (n) φ(n)表示 1 1 1 ~ n − 1 n-1 n1中与 n n n互质的数的个数
对于质数 n n n,那么肯定 φ ( n ) = n − 1 \varphi (n)=n-1 φ(n)=n1


埃氏筛 O ( n l o g n ) O(nlogn) O(nlogn)
我们知道对于一个正整数分解质因数会有: n = p 1 c 1 ∗ p 2 c 2 ∗ . . . ∗ p m c m n=p_1^{c_1}*p_2^{c_2}*...*p_m^{c_m} n=p1c1p2c2...pmcm
先给出公式 φ ( n ) = n ∗ ( 1 − 1 p 1 ) ∗ ( 1 − 1 p 2 ) ∗ . . . ∗ ( 1 − 1 p n ) \varphi (n)=n*(1- \frac{1}{p_1})*(1- \frac{1}{p_2})*...*(1- \frac{1}{p_n}) φ(n)=n(1p11)(1p21)...(1pn1)
证明——
假设 n n n只有两个质因数 p 1 p_1 p1 p 2 p_2 p2,那我们的 φ ( n ) \varphi (n) φ(n)先要筛去 p 1 p_1 p1 p 2 p_2 p2的倍数, φ ( n ) = n − n p 1 − n p 2 \varphi (n)=n-\frac{n}{p_1}-\frac{n}{p_2} φ(n)=np1np2n
但是对于 p 1 p_1 p1 p 2 p_2 p2的公倍数,我们好像多筛去了一次,所以我们要加上 φ ( n ) = n − n p 1 − n p 2 + n p 1 ∗ p 2 \varphi (n)=n-\frac{n}{p_1}-\frac{n}{p_2}+\frac{n}{p_1*p_2} φ(n)=np1np2n+p1p2n
φ ( n ) = n ∗ ( 1 − 1 p 1 − 1 p 2 + 1 p 1 ∗ p 2 ) \varphi (n)=n*(1-\frac{1}{p_1}-\frac{1}{p_2}+\frac{1}{p_1*p_2}) φ(n)=n(1p11p21+p1p21)
φ ( n ) = n ∗ ( 1 − 1 p 1 ) ∗ ( 1 − 1 p 2 ) \varphi (n)=n*(1- \frac{1}{p_1})*(1- \frac{1}{p_2}) φ(n)=n(1p11)(1p21)

然后我们推到多个质因数,就是 φ ( n ) = n ∗ ( 1 − 1 p 1 ) ∗ ( 1 − 1 p 2 ) ∗ . . . ∗ ( 1 − 1 p n ) \varphi (n)=n*(1- \frac{1}{p_1})*(1- \frac{1}{p_2})*...*(1- \frac{1}{p_n}) φ(n)=n(1p11)(1p21)...(1pn1)


∑ i = 1 n g c d ( i , n ) = ∑ k ∣ n φ ( n / k ) ∗ k \sum_{i=1}^{n}gcd(i,n)=\sum_{k|n}\varphi(n/k)*k i=1ngcd(i,n)=knφ(n/k)k
证明——
g c d ( i , n ) = k gcd(i,n)=k gcd(i,n)=k,那么 g c d ( i / k , n / k ) = 1 gcd(i/k,n/k)=1 gcd(i/k,n/k)=1
x = i / k x=i/k x=i/k,那么 g c d ( x , n / k ) = 1 gcd(x,n/k)=1 gcd(x,n/k)=1 g c d ( x ∗ k , n ) = k gcd(x*k,n)=k gcd(xk,n)=k
1 1 1 ~ n / k − 1 n/k-1 n/k1中与 n / k n/k n/k互质的数的个数,再乘上个数 k k k,即原来的式子可以转化成 ∑ φ ( n / k ) ∗ k \sum \varphi(n/k)*k φ(n/k)k


#关于这道题

∑ i = 1 n − 1 ∑ j = i + 1 n g c d ( i , j ) \sum_{i=1}^{n-1}\sum_{j=i+1}^{n}gcd(i,j) i=1n1j=i+1ngcd(i,j)
我们可以倒着来看,转换成(因为倒着好处理) ∑ i = 2 n ∑ j = 1 i − 1 g c d ( i , j ) \sum_{i=2}^{n}\sum_{j=1}^{i-1}gcd(i,j) i=2nj=1i1gcd(i,j)
∑ i = 2 n ∑ j = 1 i − 1 ∑ k ∣ i k ∗ [ g c d ( i , j ) = = k ] \sum_{i=2}^{n}\sum_{j=1}^{i-1}\sum _{k|i}k*[gcd(i,j)==k] i=2nj=1i1kik[gcd(i,j)==k]
∑ i = 2 n ∑ k ∣ i k ∗ ∑ j = 1 i − 1 [ g c d ( i , j ) = = k ] \sum_{i=2}^{n}\sum _{k|i}k*\sum_{j=1}^{i-1}[gcd(i,j)==k] i=2nkikj=1i1[gcd(i,j)==k]
∑ i = 2 n ∑ k ∣ i k ∗ ∑ j = 1 i − 1 [ g c d ( i / k , j / k ) = = 1 ] \sum_{i=2}^{n}\sum _{k|i}k*\sum_{j=1}^{i-1}[gcd(i/k,j/k)==1] i=2nkikj=1i1[gcd(i/k,j/k)==1]
∑ i = 2 n ∑ k ∣ i k ∗ ∑ j = 1 i / k − 1 [ g c d ( i / k , j ) = = 1 ] \sum_{i=2}^{n}\sum _{k|i}k*\sum_{j=1}^{i/k-1}[gcd(i/k,j)==1] i=2nkikj=1i/k1[gcd(i/k,j)==1]
∑ i = 2 n ∑ k ∣ i k ∗ φ ( i / k ) \sum_{i=2}^{n}\sum _{k|i}k*\varphi(i/k) i=2nkikφ(i/k)

我们预处理 φ \varphi φ值,最后求一个前缀和就行了


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1000010
#define LL long long
#define db double
using namespace std;

LL T, n[N], maxn, f[N], zs[N], sum[N], tot;
bool mark[N];
db phi[N];

int main()
{
	scanf ("%lld", &T);
	for (LL i = 1; i <= T; i++)
	  scanf ("%lld", &n[i]),
	  maxn = max (maxn, n[i]);
	for (LL i = 1; i <= maxn; i++) phi[i] = i;
	for (LL i = 2; i <= maxn; i++)
	  if (phi[i] == i)
	  {
	  	phi[i]--;
	  	for (int j = i + i; j <= maxn; j += i)
	  	  phi[j] *= ((db)1 - (db)1 / (db)i);
	  }
	for (LL i = 2; i <= maxn; i++)
	  for (LL j = 1; j <= maxn / i; j++)
	    f[i * j] += phi[i] * j;
	for (LL i = 1; i <= maxn; i++)
	  sum[i] = sum[i - 1] + f[i];
	for (LL i = 1; i <= T; i++)
	  printf ("%lld\n", sum[n[i]]);
	return 0;
}

你可能感兴趣的:(数论)