题目描述
有一天,TIBBAR和LXL比赛谁先算出1~N这N个数中每任意两个不同的数的最大公约数的和。LXL还在敲一个复杂而冗长的程序,争取能在100s内出解。而TIBBAR则直接想1s秒过而获得完胜,请你帮他完成这个任务。
输入格式
共一行,一个正整数N。
输出格式
共一行,一个数,为1~N这N个数中每任意两个不同的数的最大公约数的和。
输入输出样例
输入 #1 复制
10
输出 #1 复制
67
说明/提示
对于40%的数据,2≤N≤2000.
对于100%的数据,2≤N≤2000000.
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=2e6+5;
ll p[N],n;ll phi[N];bool notp[N];
void seive(ll n){
phi[1] = 1;
for(ll i=2;i<=n;++i) {
if(!notp[i]) p[++p[0]] = i, phi[i] = i-1;
for(ll j=1;j<=p[0] && i*p[j]<=n;++j) {
notp[i*p[j]] = 1;
if(i%p[j]==0){phi[i*p[j]]=phi[i]*p[j];break;}
phi[i*p[j]] = phi[i]*(p[j]-1);
}
}
for(ll i=1;i<=n;++i) phi[i] += phi[i-1];
}
ll cal(ll n,ll m){
ll ans = 0;ll r;
for(ll i=1;i<=min(n,m);i=r+1) {
r = min(n/(n/i), m/(m/i));
ans += (phi[r]-phi[i-1]) * (n/i) * (m/i);
}
return ans;
}
int main(){
scanf("%lld",&n);
seive(n);
printf("%lld\n",(cal(n,n)-n*(n+1)/2)/2);
}