1. 程式人生 > >【[SDOi2012]Longge的問題】

【[SDOi2012]Longge的問題】

\(\sum_{i=1}^ngcd(i,n)\)

考慮列舉\(gcd\),現在答案變成這樣

\(\sum_{d|n}d*f(d)\)

\(f(d)=\sum_{i=1}^n [gcd(i,n)==d]\)

考慮一下\(f(d)\)如何求

顯然\(f(d)=\varphi(n/d)\)

因為所有與\(n/d\)互質的數乘上\(d\)就是和\(n\)互質的數了

所有答案就是\(\sum_{d|n}d*\varphi(n/d)\)

程式碼

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define re register
#define LL long long
#define maxn 65580
inline int read()
{
    char c=getchar();
    int x=0;
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9')
        x=(x<<3)+(x<<1)+c-48,c=getchar();
    return x;
}
int phi[maxn],p[maxn],f[maxn];
LL n,ans;
int U;
inline LL solve(LL x)
{
    if(x<=U) return phi[x];
    LL now=1;
    for(re int i=1;i<=p[0];i++)
    if(x%p[i]==0)
    {
        LL tot=1;
        while(x%p[i]==0) tot*=p[i],x/=p[i];
        now*=(p[i]-1)*(tot/p[i]);
        if(x==1) break;
    }
    if(x!=1) now*=(x-1);
    return now;
}
int main()
{
    scanf("%lld",&n);
    f[1]=1,phi[1]=1;
    U=std::sqrt(n);
    for(re int i=2;i<=U;i++)
    {
        if(!f[i]) p[++p[0]]=i,phi[i]=i-1;
        for(re int j=1;j<=p[0]&&p[j]*i<=U;j++)
        {
            f[p[j]*i]=1;
            if(i%p[j]==0)
            {
                phi[p[j]*i]=phi[i]*p[j];
                break;
            }
            phi[p[j]*i]=phi[i]*(p[j]-1);
        }
    }
    for(re LL i=1;i*i<=n;i++)
    if(n%i==0)
    {
        ans+=i*solve(n/i);
        if(n/i!=i) ans+=(n/i)*solve(i);
    }
    std::cout<<ans;
    return 0;
}