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; }