UVA11417 GCD

题目链接
\(T ≤ 100\) \(n ≤ 500\)
唔,看数据范围,暴力可过.
时间复杂度\(O(T * n ^ 2)\)

#include <iostream>
#include <cstdio>
using namespace std;

int gcd(int a,int b) {
    while(b ^= a ^= b ^= a %= b) ;
    return a;
}

int main() {
    int n = 1;
   
    while(scanf("%d",&n) && n) { 
        long long ans = 0;
        for(int i = 1;i <= n;++ i) {
            for(int j = i + 1;j <= n;++ j) {
                    ans += 1LL * gcd(i,j);
            }
        }
        printf("%lld\n",ans);
    
    } 
}

然则还可以用莫比乌斯反演

#include <iostream>
#include <cstdio>
#define ll unsigned long long
const ll maxN= 1000+6;;

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 <= 1000;++ i) {
        if( !vis[i] ) {
            prime[++ num] = i;
            mu[i] = -1;
        }
        for(ll j = 1;j <= num && prime[j] * i <= 1000;++ 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 <= 1000;++ 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;
}
posted @ 2018-08-28 17:34  Rlif  阅读(232)  评论(0编辑  收藏  举报