UVA11426 GCD

题目链接
(T≤100)
(n≤40000000)

解法一:莫比乌斯反演

打算用莫比乌斯反演水一发.
大概在
(O(T*n*sqrt{n}))
UVA评测机真快,竟然过了.

#include <iostream>
#include <cstdio>
#define ll unsigned long long
const ll maxN= 40000000 + 7;

bool vis[maxN];
ll prime[maxN];
ll mu[maxN];
ll sum[maxN];

void init() {
    ll num = 0;
    vis[1] = 1;
    mu[1] = 1;
    for(ll i = 2;i <= 40000000;++ i) {
        if( !vis[i] ) {
            prime[++ num] = i;
            mu[i] = -1;
        }
        for(ll j = 1;j <= num && prime[j] * i <= 40000000;++ j) {
            vis[i * prime[j]] = true;
            if(i % prime[j] == 0) {
                mu[i * prime[j]] = 0;
                break;
            }
            mu[i * prime[j]] = -mu[i];
        }
    }
    for(ll i = 1;i <= 40000000;++ i) 
        sum[i] = sum[i - 1] + mu[i];
    return;
}

ll slove(ll n,ll k) {
    ll ans = 0;
    n /= k;
    for(ll l = 1,r;l <= n;l = r + 1) {
        r = n / (n / l);
        ans += ( sum[r] - sum[l - 1] ) * (n / l) * (n / l); 
    }
    return ans;
}

int main() {
    ll n = 1;
    init();
    while(scanf("%llu",&n) && n) {	
        ll ans = 0;
        for(ll i = 1;i <= n;++ i) 
            ans += i * slove(n,i);
        printf("%llu
",(ans - (n + 1) * n / 2) / 2);
    }
    return 0;
}

解法2:利用phi

考虑每个数(x)被当做(Gcd)对答案的贡献.

[GCD(i,j) = x ]

转化成

[GCD(i/x,j/x) == 1 ]

这个题跟GCD差不多
我也是写了题解

#include <iostream>
#include <cstdio>
const int maxN = 40000000 + 7;

int prime[7000000];
long long phi[maxN];

void init() {
	int num = 0;
    phi[1] = 1;
    for(int i = 2;i < maxN;++ i) {
        if( !phi[i] ) {
            prime[++ num] = i;
            phi[i] = i - 1;
        }
        for(int j = 1;j <= num && prime[j] * i < maxN;++ j) {
            if(i % prime[j] == 0) {
                phi[i * prime[j]] = phi[i] * prime[j];
                break;
            }
            phi[i * prime[j]] =  phi[i] *( prime[j] - 1);
        }
    }   
	for(int i = 2;i < maxN;++ i) 
		phi[i] += phi[i - 1];
	return ;
}

int main() {
	int fuck = 1;
	int n;
	init();
	while(fuck) {
		scanf("%d",&n);
		if(!n) break;
		long long sum = 0;
		for(int i = 1;i < n;++ i) {
			sum += ( phi[n / i] - 1 ) * i;
		}
		printf("%lld
",sum);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/tpgzy/p/9549974.html