题目大意:
求 (sum_{i=1}^{N}sum_{j=i+1}^{N}gcd(i,j))
解题报告:
我们设答案为(s[n])
那么(s[n])表示为(s[n]=sum_{i=1}^{n}f[n])
其中(f[i]=sum_{j=1}^{j=n}gcd(i,j)),我们可以拆开(f[i]):
(f[i]=sum_{j=1}^{i}j*g[i,j])
(g[n,i])为满足(gcd(n,j)==i)的j的个数,那么可以看出(gcd(n,j)==j)等价于(gcd(n/i,j/i)=1),所以实质上就是(phi(n/i))
综上我们可以先求出(phi),推出(f[i])之后再求出(s[i])即可,其中推(f[i])我们可以像线性筛一样的去推出,这样复杂度就是O(n)的了
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=4000005;
int phi[N],prime[N],num=0;bool vis[N];
void solve(){
int to;
phi[1]=1;
for(int i=2;i<N;i++){
if(!vis[i]){
prime[++num]=i;
phi[i]=i-1;
}
for(int j=1;j<=num && i*prime[j]<N;j++){
to=i*prime[j];vis[to]=true;
if(i%prime[j])phi[to]=phi[i]*(prime[j]-1);
else{
phi[to]=phi[i]*prime[j];
break;
}
}
}
}
ll f[N],ans[N];
void work()
{
solve();
for(int i=1;i<N;i++)
for(int j=i+i;j<N;j+=i)
f[j]+=i*phi[j/i];
for(int i=1;i<N;i++)
ans[i]=ans[i-1]+f[i];
int n;
while(~scanf("%d",&n) && n)
printf("%lld
",ans[n]);
}
int main()
{
work();
return 0;
}