GCD - Extreme (II)
题目
题意很简单,就是给定一个N,让求出N范围内的所有gcd(i,j)的和,
时限:10s
分析
当我看见这题是时限我就觉得不简单,同时数据量N太大,都到4e6了。但是这题N范围内的答案都需要去求,因为这题没法在线处理,所以考虑暴力的优化。我们需要去枚举什么变量,可以发现两个数去找gcd是个非常麻烦的事,因为a的情况xb的情况的数量级就已经爆炸了。所以我们可以考虑枚举gcd去找a,b。
关于gcd,我们可以知道:是互质的,而互质我们可以想到欧拉函数。假如一个数b,b/c = a ,那么与a互质的共有E[a]个数,这些数乘以c之后与b的gcd就是c。所以我们就可以枚举gcd,然后再枚举gcd的倍数,然后打个表,计算一下前缀和即可。具体看代码。
AC代码
#include <iostream> #include <algorithm> #include <stdio.h> using namespace std; typedef long long ll; const ll maxn = 4e6+10; ll N; ll E[maxn],sum[maxn]; void init() { E[1] = 1; for(int i=2;i<maxn;i++){ //预处理欧拉函数值 if(!E[i]) for(int j=i;j<maxn;j+=i){ if(!E[j]) E[j]=j; E[j] = E[j]/i*(i-1); } } for(ll i = 1;i<maxn;i++){ //枚举gcd for(ll j = 2*i;j<maxn;j+=i){ //枚举gcd的倍数 sum[j] += E[j/i]*i; } } for(ll i =2;i<maxn;i++) sum[i] += sum[i-1]; //计算前缀和 } int main(){ init(); while(scanf("%lld",&N)){ if(N == 0) break; printf("%lld\n",sum[N]); } return 0; }