51nod 1040 最大公约数之和 欧拉函数+dfs枚举因子+思维

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_37428263/article/details/89179643

51nod 1040

思路:枚举因子,gcd(n,k)=x , 那么gcd( n/x , k/x)=1, 利用欧拉函数求解Euler(n/x) , 再利用公式 \sum Euler(n/x)*x即可求解

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=50;
int fac[maxn],p[maxn],cnt=0,n;
LL sum=0;
int pow(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b&1) ans=ans*a;
        a=a*a;
        b>>=1;
    }
    return ans;
}
LL Euler(LL k)
{
    if(k==1) return 1;
    LL ans=k;
    for(LL i=2;i<=floor(sqrt(k) + 0.5); i++)
    {
        if( k % i == 0) {
            ans/=1l*i;
            ans*=1l*(i-1);
            while(k%i==0) k/=1l*i;
        }
        if(k==1) break;
    }
    if(k!=1) {
        ans/=1l*k;
        ans*=1l*(k-1);
    }
    return ans;
}
void dfs(int pos,int son)
{
    if(pos==cnt) {
        //cout<<n<<endl;
        //cout<<son<<endl;
        sum+=Euler( 1l*n/son ) * son;
        //cout<<Euler(n/son)<<endl;
        //cout<<sum<<endl;
        return;
    }
    for(int i=0;i<=p[pos];i++)
    {
        dfs(pos+1,son*pow( fac[pos], i ) );
    }
    return;
}
int main()
{
    //cout<<Euler(3)<<endl;
    scanf("%d",&n);
    int k=n;
    for(int i=2;i<=floor(sqrt(n)+0.5);i++)
    {
        if(n%i==0) {
            fac[cnt]=i;
            p[cnt]=0;
            while(n%i==0) {
                p[cnt]++;
                n/=i;
            }
            cnt++;
        }
        if(n==1) break;
    }
    if(n!=1) {
        fac[cnt]=n;
        p[cnt]=1;
        cnt++;
    }
    n=k;
    /*for(int i=0;i<cnt;i++)
    {
        printf("%d %d\n",fac[i],p[i]);
    }*/
    //枚举因子
    dfs(0,1);
    //cout<<"200"<<endl;
    printf("%lld\n",sum);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_37428263/article/details/89179643