首页 > 其他分享 >欧拉函数总结

欧拉函数总结

时间:2023-08-16 21:31:37浏览次数:34  
标签:总结 ... phi 函数 int ax primes 欧拉

欧拉函数公式

$n=p_1^{k_1} * p_2^{k_2} * \ ... \ * p_n^{k_n}$ $\phi(n) = n * \displaystyle \prod_{i = 1}^{n}(1 - \frac{1}{p_i})$

试除法求欧拉函数

#include <iostream>

using namespace std;

int main()
{
    int n;
    cin >> n;
    while (n --)
    {
        int x;
        cin >> x;
        
        int res = x;
        for (int i = 2; i <= x / i; ++ i)
            if (x % i == 0)
            {
                res -= res / i;
                while (x % i == 0) x /= i;
            }
        if (x > 1) res -= res / x;
        
        cout << res << endl;
    }
}

筛法求欧拉函数

在一些情况,需要求出1到n所有数的欧拉函数,如果对每个数都使用试除法求一遍太慢了。而筛法求欧拉函数就可以用于这类问题

算法原理

下面的代码是欧拉筛的代码,在欧拉筛质数的过程中,可以顺带着求出所有数的欧拉函数值

void get_divisors(int n)
{
    for (int i = 2; i <= n; ++ i)
    {
        if (!st[i]) primes[cnt ++] = i;
        for (int j = 0; primes[j] <= n / i; ++ j)
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}
  1. 如果判定某个数p为质数,则可直接得出其欧拉函数值为p-1

图中的p表示一个质数,和代码中的primes[j]是一样的 2. 如果 i % primes[j] == 0,说明primes[j]是i的最小质因子,即i的质因数中包含primes[j],所以primes[j]对于i的质因数分解的影响只是增加了其中某个质数的指数,并没有增加质因数的种类,所以对于计算欧拉函数的影响只不过是在i的欧拉函数值基础上乘以一个primes[j]即可(对应着3式) 3.如果i % primes[j] != 0,说明 primes[j]不是i的质因子,primes[j]对于i的质因数分解的影响是增加了一个质数,这是种类增多了,所以在计算欧拉函数时就需要多乘以一个(1-1/p)和primes[j],(对应着2式)

正确性说明

之前我们说明过枚举到i时,一定可以确定i是合数还是素数了,同理,也一定已经获得了i的欧拉函数值,所以才可以通过i和primes[j]的欧拉函数确定i * primes[j]的欧拉函数

代码实现

#include <iostream>

using namespace std;

const int N = 1e6 + 10;

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

void get_divisors(int n)
{
    phi[1] = 1;
    for (int i = 2; i <= n; ++ i)
    {
        if (!st[i])
        {
            phi[i] = i - 1;
            primes[cnt ++] = i;
        }
        for (int j = 0; primes[j] <= n / i; ++ j)
        {
            st[i * primes[j]] = true;
            if (i % primes[j] == 0)
            {
                phi[i * primes[j]] = phi[i] * primes[j]; // 对应3式
                break;
            }
            phi[i * primes[j]] = phi[i] * (primes[j] - 1); // 对应2式,只不过把primes[j]*(1 - 1 / primes[j])乘进去了
        }
    }
}
int main()
{
    int n;
    cin >> n;
    get_divisors(n);
    
    long long res = 0;
    for (int i = 1; i <= n; ++ i) res += phi[i];
    cout << res << endl;
    
    return 0;
    
}

欧拉函数的应用

欧拉定理

若n,a为正整数,且n,a互质,则: $a^{\phi(n)} = 1 (mod n)$

证明:1到n中与n互质的数设为 $x_1, x_2, ... x_{\phi(n)}$

所有项都乘以a(欧拉定理中与n互质的a),得到 $ax_1, ax_2, ... ax_{\phi(n)}$

如果满足 $ax_1 * ax_2 * ... * ax_{\phi(n)} = x_1 * x_2 * ... * x_{\phi(n)} (mod n)$

即 $a^{\phi(n)} * (x_1 * x_2 * ... * x_{\phi(n)}) = x_1 * x_2 * ... * x_{\phi(n)} (mod n)$

因为 $x_1, x_2, ... x_{\phi(n)}$ 所有数都是与n互质的,所以他们的乘积 $ x_1 * x_2 * ... * x_{\phi(n)} $ 也是与n互质的,所以根据某个定理 可以得到$a^{\phi(n)} = 1 (mod n)$

这里的某个定理还需要回学校看一下书,记不太清了

所以说我们的主要任务就是如何证明 $ax_1 * ax_2 * ... * ax_{\phi(n)} = x_1 * x_2 * ... * x_{\phi(n)} (mod n)$ ,即证明 $ax_i$ 和 $x_i$一一对应(顺序可能不同),因为 $ax_1, ax_2, ... ax_{\phi(n)}$ 是从 $x_1, x_2, ... x_{\phi(n)}$ 转变而来,所以一定是 $\phi(n)$ 项,但是乘以a之后可能有 $ax_i == ax_j$,这样的话$ax_1, ax_2, ... ax_{\phi(n)}$ 中实质上就不是 $\phi(n)$ 项了,所以我们想要证明的自然是不成立的,但是假设存在 $ax_i = ax_j (mod n)$ ,那么 $n | a(x_i - x_j)$,因为n和a互质,所以 $n | x_i - x_j$,但是所有的x都是比n小的数,这个结果显然是不成立的,所以我们的假设也不成立,所以证明了生成的数中两两modn不同余,所以也就证明了 $ax_i$ 和 $x_i$一一对应,所以欧拉定理也就成立了 证明过程有些粗糙,可能存在问题,暂定这样写

求解最大公约数为某一特定值的数对个数

给定整数 $N$,求 $0 ≤ x,y ≤ N$ 且 $GCD(x,y)$ 为1的数对 $(x,y)$ 有多少对

算法原理 求解$gcd(x, y) = 1$的(x, y),这么看真的很难和欧拉函数建立起联系 但是当我加入$x > y$的条件时,这个问题就转变为了求比x小且与x互质的数的个数,此时很明显就是使用欧拉函数进行求解 同时可以发现当$x < y$时,答案数和$x > y$是一样的 最后特判$x = y$的情况即可 绿色点代表$x > y$时一些满足条件的数对,$x < y$的情况与其关于$y=x$的曲线对称 红色线表示$x = y$的直线 黄色点表示$x = y$时那一个满足条件的数对

流程

  1. 因为x会在区间内变化,所以每次求解需要多次查询,故先使用线性筛预处理所有可能数值的欧拉值
  2. 枚举x进行求解(范围参照上方图片进行推断)

代码实现

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;

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

void init(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()
{
    init(N - 1);
    
    int x;
    cin >> x;
    
    int res = 1;
    for (int j = 1; j <= x; ++ j) res += phi[j] * 2;
    
    cout << res << endl;
    
    return 0;
}

问题推广

给定整数 $N$,求 $1 ≤ x,y ≤ N$ 且 $GCD(x,y)$ 为p的数对 $(x,y)$ 有多少对

算法原理 设$x' = \frac{x}{p}, y' = \frac{y}{p}$ 求解$gcd(x, y) = p$的数对$(x,y)$的个数可以等价为求解 $gcd(x', y') = 1$ 的数对$(x', y')$的个数 根据以下条件可推导出 $1 \leq \frac{x}{p}, \frac{y}{p} \leq \frac{N}{p}$, 即$1 \leq x', y' \leq \frac{N}{p}$ $$ \left{
\begin{array} \ 1 \leq x, y \leq N \ p \leq x \ p \leq y \end{array} \right. $$

综上所述,目前的问题已经等价为

给定整数 $N$,求 $1 ≤ x,y ≤ \frac{N}{p}$ 且 $GCD(x,y)$ 为1的数对 $(x,y)$ 有多少对

按照原问题的解法做即可

标签:总结,...,phi,函数,int,ax,primes,欧拉
From: https://blog.51cto.com/u_14882565/7113860

相关文章

  • 今天遇到的bug总结
    1、BindingException:Parameter'name'notfound.Availableparametersare[employee,param1]这是我在使用xml文件编写SQL语句,来新增员工时遇到的报错,写着找不到参数"name",应该写做employee.name,后发现是我在mapper的intsave(Employeeemployee)方法中写了@Param("employee......
  • HTML5总结
    一、认识HTML5      (1)H5即是HTML的一个最新的版本,也是web的一个标准。(2)结合CSS3中的内容如:圆角、动画、过渡等效果,提高用户的体验。    (3)新增了javascript的api,使得操作dom更加的方便。(4)还增加了与硬件结合的功能:定位、重力感应.硬件访问......
  • 2023.8.16 关于先前函数内外声明变量差异问题的答案
    答案:编译器无法在编译时求得一个非常量的值,它只能在运行时通过读取变量地址来间接得到变量的值,而全局变量在编译时就必须确定其值,故C有静态存储区数据必须用常量初始化的规定。在编译时只能用常量去初始化一个静态存储区的数据,而不能用“读取某个变量的内容”来初始化。来源:外部......
  • 无涯教程-Perl - sprintf函数
    描述此函数使用FORMAT基于LIST中的值返回格式化的字符串。本质上与printf相同,但是返回格式化的字符串而不是将其打印。语法以下是此函数的简单语法-sprintfFORMAT,LIST返回值此函数返回SCALAR(格式化的文本字符串)。例以下是显示其基本用法的示例代码-#!/usr/bin/......
  • SQL注入-mysql绕过函数注入
    1.判断注入点通过测试发现,这里过滤了空格和等于号。所以咱们用/**/代替空格,用like代替=,最后将构造的语句进行url编码,使用的是小葵转化工具。所以咱们构造如下语句。//and//1//like//1结果如下图,页面正常显示。接着咱们再构造如下语句。/**/and/**/1/**/like/**/2发现页面报错,说明存......
  • Streamlit 讲解专栏(五):探索强大而灵活的 st.write() 函数
    文章目录1前言2显示HTML的内容3显示Markdown内容4显示代码块5显示DataFrame的交互式表格6显示音频和视频7显示图表8显示图片9显示地图10显示PDF文件11显示文件下载链接12结语1前言在这篇博文中,我们将着重介绍Streamlit中一个核心而重要的函数,那就是st.write()。在之......
  • 带密匙的字符串加密解密函数(支持中文)
    usesAnsiStrings; FunctionJiaMi(Src:String;Key:String):String; var  KeyLen:Integer;  KeyPos:Integer;  offset:Integer;  dest:String;  SrcPos:Integer;  SrcAsc:Integer;  Range:Integer;  IntTemp:integer; ......
  • 经常用到的加解密函数
    以下程序可直接用,拷贝就可以了,希望可以起到抛砖引玉的作用。functionStrDecrypt(s:string;key:word):string;var i:byte;const fc1=2; fc2=3;begin //result[0]:=s[0]; setlength(result,length(s)); fori:=1tolength(s) do begin result[i]:=char(byte(s[i])xo......
  • DOTS实战技巧总结
    【USparkle专栏】如果你深怀绝技,爱“搞点研究”,乐于分享也博采众长,我们期待你的加入,让智慧的火花碰撞交织,让知识的传递生生不息!随着技术的发展,客户端方向技术也日趋讲究高性能,毕竟大世界高自由度玩法正在逼近,在这一趋势下,Unity也是催生出了DOTS这一高性能技术方案,这一解决方案讲......
  • 函数性能探测:更简单高效的 Serverless 规格选型方案
    作者:拂衣、丛霄2019年Berkeley预测Serverless将取代Serverful计算成为云计算新范式。Serverless为应用开发提供了一种全新系统架构。借助2023年由OpenAI所带来的AIGC风潮,以阿里云函数计算FC、AWSLambda为代表的Serverless以其更高成本效益、更简化的后端代码......