[c++]gcd(数论)

自己的一个小结

文章目录

    • 题目描述
      • 输入
      • 输出
      • 样例输入
      • 样例输出
      • 提示
    • 思路
    • 看看代码有利于理解

题目描述

给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对?

输入

一个整数
1<=N<=1000000

输出

一个整数

样例输入

4

样例输出

4

提示

【样例解释】
(2,2),(2,4),(3,3),(4,2)

思路

本文所有的P,均表示质数)
对于x,y 1 <= x,y <= n,且gcd(x,y) = P
由此,我们很容易相当欧拉筛法(Euler)

φ φ φ:是小于n的正整数中与n互质的数的数目( φ φ φ(1) = = = 1 1 1

注明:源自百度
我们假设gcd( x x x, y y y) = = = 1 1 1,则一定有 gcd( x x x × \times × P, y y y × \times × P) = = = P
我们不妨设 x x x <= y y y,则我们可以得出 1 1 1 <= x x x <= y y y <= n P {n} \over {P} Pn
所以我们可以先花( O ( n ) O(n) On)的时间算出 φ φ φ
然后我们只需要将 1 至 ( n P {n} \over {P} Pn)以内的所有 φ φ φ值乘二减一后加起来即可,(这些数同时乘以P后,不就是gcd( x x x × \times × P, y y y × \times × P) = = = P了吗)
数学表达: ∑ i = 1 t o t ∑ j = 1 n P [ i ] ( \sum_{i = 1}^{tot}\sum_{j = 1}^{{n} \over {P[i]}}( i=1totj=1P[i]n(ans+= φ φ φ(j) × \times × 2) - 1 1 1
乘二是因为我们假设的是 x x x <= y y y 的情况,然而实际上,将 x x x, y y y的值对调又可以对答案做出贡献,可是我们还需要减去一个一,这是因为(1 × \times × P,1 × \times × P)= P显然只有一组,所以我们需要减去一个一
总而言之,这里可用前缀和思想,但是好像空间过不去……

看看代码有利于理解

#include
#define LL long long
#define reg register
#define M 10000000
 
int n,tot;
 
LL ans;
int phi[M + 5],prime[M + 5];
bool vis[M + 5];
 
void Euler(int N){
    phi[1] = 1;
    for (reg int i = 2;i <= N; ++ i){
        if ( ! vis[i]){
            prime[ ++ tot] = i;
            phi[i] = i - 1;
        }
        for (reg int j = 1;j <= tot; ++ j){
            if (prime[j] * i > N)
                break;
            vis[prime[j] * i] = true;
            if (i % prime[j] == 0){
                phi[i * prime[j]] = prime[j] * phi[i];
                break;
            } else
                phi[i * prime[j]] = (prime[j] - 1) * phi[i];
        }
    }
}
int main(){
    scanf("%d",&n);
    Euler(n);
    for (reg int i = 1;i <= tot; ++ i){
        int g = n / prime[i];
        LL sum = 0;
        for (reg int j = 1;j <= g; ++ j)
            sum += 1ll * phi[j];
        ans += (sum * 2 - 1);
    }
    printf("%lld\n",ans);
    return 0;
}
 

你可能感兴趣的:(考试专用题,数论)