题目要你求sigma gcd(i,N) 1<=i<=N
首先要知道一个式子gcd(i,N)=p => gcd(i/p,N/p)=1
以N=12举例
gcd=1的个数就是与12互质的数字的个数,也就是12的欧拉函数值,12与1,5,7,11的gcd
gcd=2的个数包含了12/2=6的欧拉函数值,也就是12与2,10的gcd
gcd=3的个数包含了12/3=4的欧拉函数值,也就是12与3,9的gcd
这样从i=1,i*i<=n,找到n%i==0的所有i*euler(n/i)就已经找到了大部分的gcd了
剩下的则是有gcd包含了几个素数相乘
可以知道gcd(i,N)全部都是N的因子,公约数嘛
这些因子有些比√n大,有些比√n小
通过之前的式子,我们的思路是找到N所有可能的gcd=P,累加P*euler(N/P)
在我们循环i=1,i*i<=n 找到N%i==0的过程中,找到的这个i因子是小等于√N的
但是如果i*i<N,那么N/i 一定大于√N并且也是N的因子
所以循环里找到这些对应有两个因子的i 进行累加
题目代码
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; typedef long long LL; LL euler(LL n){ LL ans=n; for(LL 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; } int main(){ LL n; while(~scanf("%lld",&n)){ LL sum=0; for(LL i=1;i*i<=n;i++) if(n%i==0){ sum+=i*euler(n/i); if(i*i<n)sum+=(n/i)*euler(i); } printf("%lld ",sum); } return 0; }