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;
}