欧拉函数和最大公约数的应用

来源:互联网 发布:js使用对象进行查找值 编辑:程序博客网 时间:2024/05/30 23:33
   这种问题一般都是给出限制条件:给你一个数N(N一般很大),使得在1~N之间能够找到X使得X满足GCD(X,N)>=M,然后求解相关问题.

分析:这是一种统计类型的问题.比较容易想到的解法就是枚举GCD(X,N)的值,对于枚举到的某个GCD(X,N)的值d,如果令N=p*d,X=q*d,那么GCD(X,N)=d,一定有p,q互质,又有X<=N,则q<=p,而这样的q的个数正好对应p的欧拉函数,即满足GCD(X,N)=d的X的个数为N/d的欧拉函数值.

应用1:给出N和M,求有多少个X满足1<=X<=N,并且(X,N)>=M.

解题思路:对于这个问题,因为只需要求出满足题意的X的个数,所以可以枚举最大公约数d,而满足gcd(X,N) = d 的X的个数就是N/d的欧拉函数,把这些d对应的N/d的欧拉函数值求和即可。

       LL res=0,i;        for(i=1;i*i<=n;i++)        {            if(n%i==0)            {                if(i>=m)                    res+=euler(n/i)*i;                if(i*i!=n&&n/i>=m)                    res+=euler(i)*(n/i);            }        }        printf("%lld\n",res);

应用2: 给你一个数N,使得在1~N之间能够找到x使得x满足gcd( x , N ) >= M,求解gcd(x,N)的和.
分析:这个题要求gcd(X,N)的和,因为上一题已经求出了满足题意的个数,所以只需要在上一个应用的基础上乘以最大公约数就是最终答案。

        LL res=0,i;        for(i=1;i*i<=n;i++)        {            if(n%i==0)            {                if(i>=m)                    res+=euler(n/i)*i;                if(i*i!=n&&n/i>=m)                    res+=euler(i)*(n/i);            }        }        printf("%lld\n",res);

应用3:给你一个数N,使得在1~N之间能够找到x使得x满足gcd( x , N ) >= M,求解X的和.
分析:这个题和前两个题基本上一样,只需要在枚举最大公约数d时,求出gcd(X,N) = d 的所有X的和即可。根据上面可以得出:满足条件的X个数有euler(N/d)个,所以只需要求出不超过N/d且与N/d互素的那些数的和,然后乘以d就是最大公约数为d时对应的部分结果。而不超过N/d且与N/d互素的那些数的和 = N/d * euler(N/d) / 2,注意当N/d = 1时,结果是1而不是0。了解了这些,就可以解决这个题了。
除了1、2以外,所有数的欧拉函数都是偶数。
如果k <= n 并且 (k,n) = 1, 那么(n-k, n) = 1;

#include<stdio.h>#include<string.h>#include<iostream>#include<math.h>#include<algorithm>using namespace std;#define M 1000000007typedef long long LL;LL euler(LL n){    LL ans=n,i;    for(i=2;i*i<=n;i++)    {        if(n%i==0)        {            ans=ans/i*(i-1);            while(n%i==0)                n/=i;        }    }    if(n>1)        ans=ans/n*(n-1);    return ans;}LL euler_sum(LL n){    if(n==1)        return 1;    return n*(euler(n))/2;}int main(){    int t;    LL n,m;    scanf("%d",&t);    while(t--)    {        scanf("%lld%lld",&n,&m);        LL res=0,i;        for(i=1;i*i<=n;i++)        {            if(n%i==0)            {                if(i>=m)                {                    res+=euler_sum(n/i)*i;                    res%=M;                }                if(i*i!=n&&n/i>=m)                {                    res+=euler_sum(i)*(n/i);                    res%=M;                }            }        }        printf("%lld\n",res);    }    return 0;}        
0 0
原创粉丝点击