GCD

来源:互联网 发布:sql导入access数据库 编辑:程序博客网 时间:2024/06/05 21:04

题目来源: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<map>#include<stack>#include<queue>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<iostream>#include<string>#define mem(a,b) memset(a,b,sizeof(a))#define MAXN 4000010using 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]);}
0 0
原创粉丝点击