ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AcWing 220. 最大公约数

2022-05-21 16:01:35  阅读:159  来源: 互联网

标签:phi frac gcd int 质数 样例 最大公约数 220 AcWing


题目传送门

一、视频教程

https://www.bilibili.com/video/BV1cP4y1c7q8

二、解题思路

最开始读错题,成了:
\(1<=x,y<=N\),并且\(gcd(x,y)=1\)有多少数对?

这不就是在计算\(\displaystyle \sum_{i=1}^{N}φ(i)\)吗?

其实本题不是说\(gcd(x,y)=1\),而是说\(gcd(x,y)=p\),其中\(p\)是质数

1、解读样例

先来看一下样例:\(n=4\)时,答案是\(4\)。
我们手动枚举一下:
\(gcd(2,2)=2\),\(gcd(3,3)=3\),\(gcd(2,4)=2\),\(gcd(4,2)=2\)

就这四个,因为只有这几种组合,最大公约数才是质数,组数是\(4\)组。
可以看得出来,由这个样例推出:这里\(gcd(2,4)=gcd(4,2)=2\)被看成了两组,也说是说对于不同的\(x,y\),视为两组结果。
小结:手动计算一下样例非常重要,可以帮我们更深刻理解题意!

2、推式子

这是一个最大公约数的典型转化技巧:把\(p\)除过来,形成:

\[gcd(\frac{x}{p},\frac{y}{p})=1 \]

为什么要除过来呢?因为\(p\)的取值是多种多样的,我们不知道\(p\)具体是什么,如果我们把\(p\)除过来,是不是就会简化很多呢?其实就是从骨子里想要用欧拉函数解决问题,不搞成和欧拉函数差不多的样子,怎么能用得上人家呢?除吧,技巧,背吧,技巧~

这是在最大公约数中最常见的变化技巧之一,后面还有比较难的莫比乌斯变换,以后再讲~

现在,可以视\(x'=\frac{x}{p},y'=\frac{y}{p}\),即就是\(gcd(x',y')=1\),这不就是用上欧拉函数了吗?只不过数据范围有了变化,变成了\(1<=x',y'<=\frac{N}{p}\)

到了这里,\(p\)是啥呢?它是需要在\(1\sim N\)之间枚举的每一个质数,用线性筛法求得,然后遍历就可以计算了。

   for (int i = 0; i < cnt; i++) {
        int p = primes[i]; //枚举1~n中的所有质数p
        ......
   }

如果\(p\)被枚举到,比如现在\(p=2\),那我们如何来求\(gcd(x',y')=1\)的数对个数呢?
这就是简单的欧拉函数+求和(可以使用前缀和优化)啊~
数据范围:\(1<=x',y'<=\frac{N}{p}\)

像\(201\)一样,提前计算出前缀和,这样避免每次循环计算:

  //维护一个前缀和,本题中phi[1]=1
    for (int i = 1; i <= n; i++) s[i] = s[i - 1] + phi[i];

这里有一个第一象限\(45^。\)直线上点的问题,就是\(x'=y'\)时,我们分别在两下方和上方计算了两次,需要再减去\(1\)。

  res += s[n / p] * 2 - 1; //推导的公式

\[\sum_{i=1}^N (2 * \sum_{i=1}^{\frac{N}{p}} φ(i)-1 ) \]

三、实现代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e7 + 10; //这家伙好大啊

int primes[N], cnt;
bool st[N];
int phi[N];
LL s[N];

void euler(int n) {
    phi[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!st[i]) {
            primes[cnt++] = i;
            phi[i] = i - 1;
        }
        for (int j = 0; primes[j] * i <= n; j++) {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) {
                phi[i * primes[j]] = phi[i] * primes[j];
                break;
            }
            phi[i * primes[j]] = phi[i] * (primes[j] - 1);
        }
    }
}

int main() {
    int n;
    cin >> n;
    euler(n);
    //维护一个前缀和,本题中phi[1]=1
    for (int i = 1; i <= n; i++) s[i] = s[i - 1] + phi[i];

    LL res = 0;
    for (int i = 0; i < cnt; i++) {
        int p = primes[i];       //枚举1~n中的所有质数p
        res += s[n / p] * 2 - 1; //推导的公式
    }
    cout << res << endl;
    return 0;
}

标签:phi,frac,gcd,int,质数,样例,最大公约数,220,AcWing
来源: https://www.cnblogs.com/littlehb/p/16295256.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有