UVA11426 GCD - Extreme (II)

题目链接
\(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\n",(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\n",sum);
	}
	return 0;
}
posted @ 2018-08-28 18:07  Rlif  阅读(193)  评论(0编辑  收藏  举报