GCD - Extreme (II) (数论,欧拉函数)

题目来源:https://vjudge.net/problem/UVA-11426
【题意】
求在1-n之间所有任意两个数的的最大公因数的和。
【思路】
做完这道题,依旧感觉头脑懵懵的,看了好多篇博客方才看懂了这道题的解法,因为之前做过几道数论题,关于素数的比较多,这到题因为最大公因数就自然而然的想到了素数筛法,一直在找所谓的规律。最后终于崩溃了。。。
便搜了博客慰藉我不安的心灵,但是很多博客我发现一个共同的优点,写的让我看不懂,这就比较厉害了。终于,被我发现了一篇特别接地气的博文,此处为链接:http://www.cnblogs.com/staginner/archive/2012/10/29/2745135.html,然后接下来,就是我的叙述和理解。
因为让求的1-n区间里任两个数的最大公因数之和,所以假设gcd(n,m)=z,在这里,因为n和m的范围都是超级大,所以,不能枚举n,m,但是可以枚举m,z,或者n,z。
具体思路是:假设gcd(x,y)=1,那么当执行到x,y的时候,最后的和都要加1,那么相应的,执行到2x,2y时,最后的和都要加2,以此类推,执行到kx,ky的时候最后的和都要加k,那么这些一切的根源都归咎于gcd(x,y)=1,所以才有了上面那一句话,枚举n,z(n,m选其一,无所谓的),这里的z就是上面的1,2,。。k。枚举z的问题解决了,那么轮到n了,枚举n,假设一个值为num,那么num代表与n的最大公因数是z(1,2,3,,,,k)的个数,这里的z有好多值,但是任何的z(大于1)都可以有最根本的gcd(x,y)推出,所以算出只需要算出z=1时num的值就可以了,这个时候,就会想到欧拉函数值(小于n的数里与n互质的个数)。然后,这道题算是结束了。
【代码】

#include
#include
#include
#include
#include
#include
#include
#include
#include
#define mem(a,b) memset(a,b,sizeof(a))
#define MAXN 4000010
using namespace std;
const int INF=1e9;
typedef long long LL;
const int maxn=4e6+10;
LL euler[maxn];
LL a[maxn];
int main()
{
    LL n;
    mem(euler,0);
    euler[1]=1;
    for(int i=2; i<=maxn; i++)
    {
        if(!euler[i])//筛法求欧拉函数值
        {
            euler[i]=i-1;
            for(int j=2*i; j<=maxn; j+=i)
            {
                if(!euler[j])
                    euler[j]=j;
                euler[j]=euler[j]/i*(i-1);
            }
        }
        for(int j=1; i*j<=maxn; j++)//根据gcd(x,y)推出z不等于1的num值。
            a[i*j]+=euler[i]*j;
    }
    for(int i=1; i<=maxn; i++)//累加。成前缀合
        a[i]+=a[i-1];
    while(~scanf("%lld",&n)&&n)
        printf("%lld\n",a[n]);
}

你可能感兴趣的:(ACM竞赛,【数论】--欧拉函数,ACM的进程)