220. 最大公约数(欧拉函数)

文章讨论了一种数学问题,其中涉及计算在一定范围内,两数的最大公约数(gcd)为质数的数对数量。通过欧拉函数和质数枚举,计算1到n之间互质数对的总数,并利用前缀和优化求解过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章目录

题意

给你一个n,请问有多少个 1 ≤ i , j ≤ n 1 \le i, j\le n 1i,jn,gcd(i, j)是一个质数。这里的i,j是无序的

思路

首先我们要先清楚gcd的含义
由于算术定理:
x = p 1 a 1 ∗ p 2 a 2 ∗ p 3 a 3 . . . ∗ p k a k . a = p 1 a 1 ∗ p 2 a 2 ∗ p 3 a 3 . . . ∗ p k a k . b = p 1 b 1 ∗ p 2 b 2 ∗ p 3 b 3 . . . ∗ p k b k . g c d ( a , b ) = x = p 1 m i n ( a 1 , b 1 ) ∗ p 2 m i n ( a 2 , b 2 ) ∗ p 3 m i n ( a 3 , b 3 ) . . . ∗ p k m i n ( a k , b k ) ( a   m o d   p i = , b   m o d   p i = 0 ) x = p_1^{a_1} * p_2^{a_2} * p_3^{a_3} ...*p_k^{a_k} \\.\\a = p_1^{a_1} * p_2^{a_2} * p_3^{a_3} ...*p_k^{a_k}\\.\\b = p_1^{b_1} * p_2^{b_2} * p_3^{b_3} ...*p_k^{b_k}\\.\\gcd(a, b) = x = p_1^{min(a_1, b_1)} * p_2^{min(a_2, b_2)} * p_3^{min(a_3, b_3)} ...*p_k^{min(a_k, b_k)}(a \ mod \ p_i = , b \ mod \ p_i = 0) x=p1a1p2a2p3a3...pkak.a=p1a1p2a2p3a3...pkak.b=p1b1p2b2p3b3...pkbk.gcd(a,b)=x=p1min(a1,b1)p2min(a2,b2)p3min(a3,b3)...pkmin(ak,bk)(a mod pi=,b mod pi=0)
换句话说,gcd(a, b)是a,b所共有因子且取个数最小的乘积。
由于题意所说gcd(a, b)是一个质数d,那么我们就要清楚a,b除了只有一个共同因子d(d的次数为1)意外没有任何一个共同因子。这就等价于 g c d ( a d , b d ) = 1 gcd(\frac{a}{d}, \frac{b}{d}) = 1 gcd(da,db)=1,那么我们只需要去找有多少对互质的数就行了。那么我们对于一个数列而言,它的欧拉函数总和,就是两个互质数对个数。可以看我的算法笔记。我们可以枚举出 1 0 7 10^7 107以内所有的质数。然后让n除上每一个质数,得到p我们要求的是1~p以内有多少对互质的数,也就是对 ϕ ( i ) \phi(i) ϕ(i)求一个前缀和。

PS:这个题目没有前缀和处理phi[1] = 1只是加1,不加2是因为x x本身顺序根本没有关系。

代码

#include<bits/stdc++.h>

#define IOS ios::sync_with_stdio(false);cin.tie(nullptr)
#define int long long 
#define endl "\n"
#define xx first
#define yy second

using namespace std;

const int N = 1e7 + 10;

int n;
int cnt, pr[N], phi[N], sum[N];
bool st[N];

void getprime(int x)
{
    phi[1] = 1;
    for(int i = 2; i <= x; i ++)
    {
        if(!st[i])
        {
            pr[cnt++] = i;
            phi[i] = i-1;
        }
        
        for(int j = 0; pr[j]*i <= x; j ++)
        {
            st[pr[j] * i] = 1;
            if(i % pr[j] == 0)
            {
                phi[i * pr[j]] = phi[i] * pr[j];
                break;
            }
            
            phi[i * pr[j]] = phi[i] * (pr[j] - 1);
        }
    }
    
    for(int i = 2; i <= N; i ++) sum[i] = sum[i-1] + phi[i];
}

signed main()
{
    IOS;
   
    int ans = 0;
    cin >> n;
    getprime(n);
    for(int i = 0; i < cnt; i ++)
    {
        int now = n / pr[i];
        ans += sum[now] * 2 + 1;
    }
    
    cout << ans << endl;
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值