nyoj 998

nyoj 998    点击这里打开题目链接

   给你一个数N,使得在1~N之间能够找到x使得x满足gcd( x ,  N  ) >= M,

求解gcd(x,N)的和


思路:一开始想到暴力法做,超时 ,后来借鉴学长经验AC:

大致思路: 用欧拉函数求 ,euler(n) 表示 1到n与n互质的数的个数,  如果n能够被 i 整除 ,

         则euler(n/i)等价于gcd(x,N)==i 的个数  (x是从1到n的所有数字)。


所以,你会想到一个for循环,因为gcd(x,N)的值为1到n  枚举  gcd为M到n,再来求和? 时间复杂度也会很高,

所以并不需要全部一一枚举 

        比如gcd(x,N)  N为  10  , 它们的gcd  只有  1,10    2,5

                                    N为15    它们的gcd  有  1,15,   3,5   

       所以它们的gcd  只需要知道1  到 根号n 而另外一个gcd   为  n/i  ;

for(i=1;i*i<=n;i++)
 {
      if(n%i==0)
      {
          if(i>=m)            sum+=i*euler(n/i);
          if(i*i!=n&&n/i>=m)  sum+=(n/i)*euler(i);  
      }
 }
注意:  第二个if  i *i!=n  因为在第一个if里面已经加过了 


下面贴个代码



#include <stdio.h>
#include <math.h>

long long euler(long long n)
{
    long long i,sum=n,temp=n;
    for(i=2;i*i<=temp;i++)
    {
        if(n%i==0)
        {
            sum=sum/i*(i-1);
            while(n%i==0)
                n/=i;
        }
    }
    if(n>1)
        sum=sum/n*(n-1);
    return sum;
}

int main()
{
    long long m,n;
    while((scanf("%lld %lld",&n,&m))!=EOF)
    {
        long long sum=0,i;
        for(i=1;i*i<=n;i++)
        {
            if(n%i==0)
            {
                if(i>=m)            sum+=i*euler(n/i);
                if(i*i!=n&&n/i>=m)  sum+=(n/i)*euler(i);
            }
        }
        printf("%lld
",sum);
    }
    return 0;
}



原文地址:https://www.cnblogs.com/coded-ream/p/7208004.html