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

小目录

    • 链接
    • 题目描述
    • 样例输入
    • 样例输出
    • 思路
    • 代码

链接

luogu P1390

题目描述

∑ i = 1 n − 1 ∑ j = i + 1 n g c d ( i , j ) \sum\limits_{i = 1}^{n-1}\sum\limits_{j = i + 1}^{n}gcd(i,j) i=1n1j=i+1ngcd(i,j)

样例输入

2
10
100

样例输出

67
13015

思路

我讨厌数论…
拆开处理
∑ i = 1 n g c d ( i , n ) \sum\limits_{i = 1}^{n}gcd(i,n) i=1ngcd(i,n)
= ∑ i = 1 n ∑ d ∣ n [ g c d ( i , n ) = = d ] ∗ d =\sum\limits_{i = 1}^{n}\sum\limits_{d|n}[gcd(i,n)==d]*d =i=1ndn[gcd(i,n)==d]d
= ∑ i = 1 n ∑ d ∣ n [ g c d ( i d , n d ) = = 1 ] ∗ d =\sum\limits_{i = 1}^{n}\sum\limits_{d|n}[gcd(\frac{i}{d},\frac{n}{d})==1]*d =i=1ndn[gcd(di,dn)==1]d
= ∑ i = 1 n ∑ d ∣ n φ ( n d ) ∗ d =\sum\limits_{i=1}^{n}\sum\limits_{d|n}\varphi(\frac{n}{d})*d =i=1ndnφ(dn)d
那么答案就可以转化为
∑ i = 2 n ∑ j = 1 ⌊ n i ⌋ φ ( i ) ∗ j \sum\limits_{i=2}^{n}\sum\limits_{j=1}^{\left\lfloor\frac{n}{i}\right\rfloor}\varphi(i)*j i=2nj=1inφ(i)j(看不懂就感性理解吧,我感觉我也不是特别懂,玄学东西

用前缀和优化

代码

JZOJ

#include
#include
#include
#include
#define ll long long

using namespace std;

int sum[1000005];
int v[1000005], phi[1000005], prime[1000005];
int n, t, tot;

void primes()
{ 
	phi[1] = 1;
	for(int i = 2; i <= 1000005; ++i)
	{
		if(!v[i]) {
			prime[++tot] = i;
			phi[i] = i - 1;
		}
		for(int j = 1; j <= tot; ++j)
		{
			int p = i * prime[j];
			if(p > 1000005) break;
			v[p] = 1;
			if(i % prime[j] == 0)
			{
				phi[p] = phi[i] * prime[j];
				break;
			}
			else phi[p] = phi[i] * (prime[j] - 1);
		}
	}
}//求欧拉函数

int main()
{
	primes();
	scanf("%d", &t);
	for(int d = 2; d <= 1000005; ++d)
		for(int i = 1; i <= 1000005 / d; ++i)
			sum[d * i] += phi[d] * i;
	for(int i = 2; i <= 1000005; ++i)
		sum[i] += sum[i - 1]; 
	for(int tt = 1; tt <= t; ++tt)
	{
		scanf("%d", &n);
		printf("%lld\n", sum[n]);
	}
	return 0;
}

Luogu

#include
#include
#include
#include
#define ll long long

using namespace std;

ll sum[2000005];
ll v[2000005], phi[2000005], prime[2000005];
int n, t, tot;

void primes()
{ 
	phi[1] = 1;
	for(int i = 2; i <= 2000005; ++i)
	{
		if(!v[i]) {
			prime[++tot] = i;
			phi[i] = i - 1;
		}
		for(int j = 1; j <= tot; ++j)
		{
			int p = i * prime[j];
			if(p > 2000005) break;
			v[p] = 1;
			if(i % prime[j] == 0)
			{
				phi[p] = phi[i] * prime[j];
				break;
			}
			else phi[p] = phi[i] * (prime[j] - 1);
		}
	}
}

int main()
{
	primes();
	scanf("%d", &n);
	for(int d = 2; d <= 2000005; ++d)
		for(int i = 1; i <= 2000005 / d; ++i)
			sum[d * i] += phi[d] * i;
	for(int i = 2; i <= 2000005; ++i)
		sum[i] += sum[i - 1]; 
	printf("%lld\n", sum[n]);
	return 0;
}

你可能感兴趣的:(数论,&,数学,数论,模拟赛,欧拉函数)