UVA 11426 GCD

题目大意:
(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;
}

原文地址:https://www.cnblogs.com/Yuzao/p/7511879.html