UVA 11426 GCD

题意:求sum(gcd(i,j),1<=i<j<=n)。

思路:首先能够看出能够递推求出ans[n],由于ans[n-1]+f(n),当中f(n)表示小于n的数与n的gcd之和

问题转化为了求f(n),由于小于n的数与n的gcd一定是n的因数,

所以f(n)能够表示为sum(i)*i,当中sum(i)表示全部和n的gcd为i的数的数量,我们要求满足gcd(a, n) = i,的个数,能够转化为求gcd(a/i, n/i) = 1的个数,

于是能够发现sun(i) = phi(n/i),这里枚举n的因数的方法仿照素数筛法,时间复杂度为O(nlogn).

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii (pair<int, int>)
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int maxn = 5000000;
//const int INF = 0x3f3f3f3f;
int n; 
LL ans[5000000];

int phi[maxn];
void phi_table(int n) {
	for(int i = 2; i <= n; i++) phi[i] = 0;
	phi[1] = 1;
	for(int i = 2; i <= n; i++) if(!phi[i])
		for(int j = i; j <= n; j+=i) {
			if(!phi[j]) phi[j] = j;
			phi[j] = phi[j] / i * (i-1);
		}
} 

void init() {
	phi_table(4000000);
	ans[1] = 0;
	for(int i = 1; i <= 4000000; i++) {
		for(int j = i*2; j <= 4000000; j+=i) {
			ans[j] += phi[j/i]*i; 
		}
	}
	for(int i = 2; i <= 4000000; i++) ans[i] += ans[i-1];
}

int main() {
    //freopen("input.txt", "r", stdin);
	init(); //cout << phi[3] << endl;
	while(scanf("%d", &n) == 1 && n) {
		cout << ans[n] << endl;
	}
    return 0;
}






原文地址:https://www.cnblogs.com/claireyuancy/p/7011162.html