P2398 GCD SUM (欧拉函数)

传送门
在这里插入图片描述

我们可以从1开始枚举最大公约数,枚举到n,求出满足gcd(x,y)==i,1<=x,y<=n,的x,y对数m,i*m累加起来就是答案。

问题是如何求满足gcd(x,y)==i,1<=x,y<=n,的x,y对数呢?

我们知道满足gcd(x,y)==1,1<=x,y<=n,的x,y对数是 2 ∗ ∑ 1 n p h i [ i ] − 1 2*\sum_{1}^{n} phi[i] -1 21nphi[i]1,
我们令x=a*i,y=b*i,gcd(x,y)==i就可以表示成gcd(a,b)==1,1<=b*i,a*i<=n,
所以转化成了gcd为1的情况。答案就是: 2 ∗ ∑ 1 n / i p h i [ i ] − 1 2*\sum_{1}^{n/i} phi[i] -1 21n/iphi[i]1

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
const int maxn = 1e5+10;
const int mx = 40;
const int mod = 1e9+7;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const int INF = 1e9+7;
//给定整数n  求满足1<=x,y<=n gcd(x,y)是素数的x y的对数 ,x y可以相同
int vis[maxn];//0表示素数
int book[maxn];//第i个素数
ll phi[maxn];//欧拉函数
ll pre[maxn];
int n;
void phi_primer()
{
    
    
    phi[1]=1;
    for(int i=2;i<=n;i++)
    {
    
    
        if(!vis[i])
        {
    
    
            book[++book[0]]=i;
            phi[i]=i-1;
        }
        for(int j=1;j<=book[0] && i*book[j]<=n;j++)
        {
    
    
            vis[i*book[j]]=1;
            if(i%book[j]==0)
            {
    
    
                phi[i*book[j]]=phi[i]*book[j];
                break;
            }
            else //i book[j]互质
            {
    
    
                phi[i*book[j]]=phi[i]*(book[j]-1);
            }
        }
    }
}

int main()
{
    
    
    scanf("%d",&n);
    phi_primer();
    for(int i=1;i<=n;i++) pre[i]=pre[i-1]+phi[i];
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
    
    
        ans = ans+ i*(pre[n/i]*2-1);
    }
    printf("%lld",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_46030630/article/details/121383801