UVA 11426 GCD - Extreme (II)
题目大意:
求 \(\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\n",ans[n]);
}
int main()
{
work();
return 0;
}