51 Nod 1040 最大公约数之和

题目链接:这里写链接内容
给出一个n,求1-n这n个数,同n的最大公约数的和。比如:n = 6
1,2,3,4,5,6 同6的最大公约数分别为1,2,3,2,1,6,加在一起 = 15
Input
1个数N(N <= 10^9)
Output
公约数之和
Input示例
6
Output示例
15

n与1-n的最大公约数的和,首先可以肯定的是,这个最大公约数一定是n的因子,那么就可以将问题化简了,1-n中每个数都和n有最大公约数,并且这些公约数都在n的因子之中,所以我们要统计每个因子使用的个数,然后分别乘以因子加起来就成功了

分析如上,那么怎么求因子的使用个数呢?就有一个转化了,很有意思,gcd(n,i)=x 1<=i<=n;
然后两边除以x,或者用式子来推的话:n*a+i*b=x —-> (n/x)*a+(i/x)*b=1 然后就是gcd(n/x,i/x)=1;
求满足此条件i的个数了,然后是不是联想到了欧拉函数,phi(n)就是1-n与n 互质的个数,互质就是最大公约数等于1啊,这里的 i/x的范围就是[1,n/x] .

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
ll oula(ll n) {
    ll res=n;
    for(int i=2; i*i<=n; i++) {
        if(n%i==0) { //第一次找到的必为素因子
            res-=res/i;
            while(n%i==0) {
                n/=i;//把该素因子全部约掉
            }
        }
    }
    if(n>1) {
        res-=res/n;
    }
    return res;
}
int main() {
    ll n;
    scanf("%lld",&n);
    ll ans=0;
    for(ll i=1; i*i<=n; i++) { //顺扫n的因子肯定是不可能的,因为该数最大为10的9次方
        //而题目限时是1秒,但是一般服务器的计算速度为10的8次方每秒,所以
        if(n%i==0) { //同时可计算两个因子
            ans+=oula(n/i)*i;
            if(n!=i*i) {
                ans+=oula(i)*(n/i);

            }
        }

    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37774171/article/details/82022066