数学知识1.3

一、简述

本文章主要介绍欧拉函数以及快速幂的相关算法。

二、欧拉函数

定义

1 ∼ N 1∼N 1N 中与 N N N 互质的数的个数被称为欧拉函数,记为 ϕ ( N ) \phi(N) ϕ(N)。若在算数基本定理中, N = p 1 a 1 p 2 a 2 … p m a m N=p^{a1}_1p^{a2}_2…p^{am}_m N=p1a1p2a2pmam,则: ϕ ( N ) = N × p 1 − 1 p 1 × p 2 − 1 p 2 × … × p m − 1 p m \phi(N)=N\times\frac{p_1−1}{p_1}\times\frac{p_2−1}{p_2}\times…\times\frac{p_m−1}{p_m} ϕ(N)=N×p1p11×p2p21××pmpm1

计算式的证明
情况1

n = 0 n=0 n=0 时,显然,因为 n = 0 n=0 n=0 时,欧拉函数的计算范围内只有 0 0 0,但是 ϕ ( 0 ) = 0 \phi(0)=0 ϕ(0)=0
n = 1 n=1 n=1 时,因为 1 1 1 与自身互素, ϕ ( 1 ) = 1 \phi(1)=1 ϕ(1)=1

情况2

n n n 为素数时,因为 1 ∼ n 1∼n 1n 都不被 n n n 整除,所以这些数都与 n n n 互素, ϕ ( n ) = n − 1 \phi(n)=n-1 ϕ(n)=n1

情况3

n n n 进行质因数分解 n = p 1 a 1 p 2 a 2 … p m a m n=p^{a1}_1p^{a2}_2…p^{am}_m n=p1a1p2a2pmam
1 ∼ n 1∼n 1n 中所有 p 1 , p 2 . . . p m p_1,p_2...p_m p1,p2...pm 的倍数去掉,剩余 n − ( n ∑ i = 1 m 1 p i ) n-(n\sum\limits_{i=1}^m\frac{1}{p_i}) n(ni=1mpi1) 个数,由于该过程 1 ∼ n 1∼n 1n 中既是 p i p_i pi 又是 p j ( i ≠ j ) p_j(i\neq j) pj(i=j) 倍数的数被重复去除,所以我们需要将这些数加回来,即 n − ( n ∑ i = 1 m 1 p i ) + ( n ∑ j , k = 1 , j ≠ k m 1 p j p k ) n-(n\sum\limits_{i=1}^m\frac{1}{p_i})+(n\sum\limits_{j,k=1,j\neq k}^m\frac{1}{p_jp_k}) n(ni=1mpi1)+(nj,k=1,j=kmpjpk1),以此类推,我们会发现这是多集合容斥计算式,总结为 ϕ ( N ) = N × p 1 − 1 p 1 × p 2 − 1 p 2 × … × p m − 1 p m \phi(N)=N\times\frac{p_1−1}{p_1}\times\frac{p_2−1}{p_2}\times…\times\frac{p_m−1}{p_m} ϕ(N)=N×p1p11×p2p21××pmpm1

模板题AcWing873.欧拉函数
题目描述

给定 n n n 个正整数 a i a_i ai,请你求出每个数的欧拉函数。

输入格式

第一行包含整数 n n n
接下来 n n n 行,每行包含一个正整数 a i a_i ai

输出格式

输出共 n n n 行,每行输出一个正整数 a i a_i ai 的欧拉函数。

数据范围

1 ≤ n ≤ 100 , 1≤n≤100, 1n100,
1 ≤ a i ≤ 2 × 1 0 9 1≤a_i≤2×10^9 1ai2×109

输入样例
3
3
6
8
输出样例
2
2
4
解题思路

根据欧拉函数的计算式计算即可,时间复杂度 O ( n a ) O(n\sqrt{a}) O(na )

C++代码
#include <iostream>
using namespace std;

int main()
{
    int n;
    cin >> n;
    while(n --)
    {
        int a;
        cin >> a;
        int res = a;
        for(int i = 2; i <= a / i; i ++)
        {
            if(a % i == 0)
            {
                res = res / i * (i - 1);
                while(a % i == 0)
                    a /= i;
            }
        }
        if(a > 1) res = res / a * (a - 1);//先除后乘可以避免数值溢出
        cout << res << endl;
    }
    return 0;
}

三、筛法求欧拉函数

思路

借用线性筛进行欧拉函数的计算

模板题AcWing874.筛法求欧拉函数
题目描述

给定一个正整数 n n n,求 1 ∼ n 1∼n 1n 中每个数的欧拉函数之和。

输入格式

共一行,包含一个整数 n n n

输出格式

共一行,包含一个整数,表示 1 ∼ n 1∼n 1n 中每个数的欧拉函数之和。

数据范围

1 ≤ n ≤ 1 0 6 1≤n≤10^6 1n106

输入样例
6
输出样例
12
解题思路

由于数据范围为 1 0 6 10^6 106,显然我们不能根据定义去依次计算再求解。我们考虑使用线性筛法的方式区计算,具体思路借助代码解释。
关于代码中 f l a g 1 flag1 flag1:根据欧拉函数计算式可知 i = p 1 a 1 p 2 a 2 … p m a m i=p^{a1}_1p^{a2}_2…p^{am}_m i=p1a1p2a2pmam ϕ ( i ) = i × p 1 − 1 p 1 × p 2 − 1 p 2 × … × p m − 1 p m \phi(i)=i\times\frac{p_1−1}{p_1}\times\frac{p_2−1}{p_2}\times…\times\frac{p_m−1}{p_m} ϕ(i)=i×p1p11×p2p21××pmpm1;而 t = p r i m e s [ j ] × i t=primes[j]\times i t=primes[j]×i,而 p r i m e s [ j ] primes[j] primes[j] 整除 i i i,故 t = p 1 a 1 p 2 a 2 … p m a m t=p^{a1}_1p^{a2}_2…p^{am}_m t=p1a1p2a2pmam,除了 t t t p r i m e s [ j ] primes[j] primes[j] 的指数比 i i i 多一,则 ϕ ( t ) = t × p 1 − 1 p 1 × p 2 − 1 p 2 × … × p m − 1 p m = p r i m e s [ j ] × i × p 1 − 1 p 1 × p 2 − 1 p 2 × … × p m − 1 p m = p r i m e s [ j ] × ϕ ( i ) \phi(t)=t\times\frac{p_1−1}{p_1}\times\frac{p_2−1}{p_2}\times…\times\frac{p_m−1}{p_m}=primes[j]\times i\times\frac{p_1−1}{p_1}\times\frac{p_2−1}{p_2}\times…\times\frac{p_m−1}{p_m}=primes[j]\times\phi(i) ϕ(t)=t×p1p11×p2p21××pmpm1=primes[j]×i×p1p11×p2p21××pmpm1=primes[j]×ϕ(i)
关于代码中 f l a g 2 flag2 flag2 i i i p r i m e s [ j ] primes[j] primes[j] 互质。则 t t t 的质因数分解会比 i i i 多一个质因数。 ϕ ( i ) = i × p 1 − 1 p 1 × p 2 − 1 p 2 × … × p m − 1 p m \phi(i)=i\times\frac{p_1−1}{p_1}\times\frac{p_2−1}{p_2}\times…\times\frac{p_m−1}{p_m} ϕ(i)=i×p1p11×p2p21××pmpm1 ϕ ( t ) = t × p 1 − 1 p 1 × p 2 − 1 p 2 × … × p m − 1 p m × p r i m e s [ j ] − 1 p r i m e s [ j ] = p r i m e s [ j ] × i × p 1 − 1 p 1 × p 2 − 1 p 2 × … × p m − 1 p m × p r i m e s [ j ] − 1 p r i m e s [ j ] = ϕ ( i ) × ( p r i m e s [ j ] − 1 ) \phi(t)=t\times\frac{p_1−1}{p_1}\times\frac{p_2−1}{p_2}\times…\times\frac{p_m−1}{p_m}\times\frac{primes[j]-1}{primes[j]}=primes[j]\times i\times\frac{p_1−1}{p_1}\times\frac{p_2−1}{p_2}\times…\times\frac{p_m−1}{p_m}\times\frac{primes[j]-1}{primes[j]}=\phi(i)\times(primes[j]-1) ϕ(t)=t×p1p11×p2p21××pmpm1×primes[j]primes[j]1=primes[j]×i×p1p11×p2p21××pmpm1×primes[j]primes[j]1=ϕ(i)×(primes[j]1)

C++代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1000010;
typedef long long LL;

int n;
int primes[N], cnt;
int euler[N];
bool st[N];

void get_eulers(int n)
{
    euler[1] = 1;//1对应的欧拉函数为1
    for(int i = 2; i <= n; i ++)
    {
        if(!st[i])//i为质数
        {
            primes[cnt ++] = i;//筛出质数
            euler[i] = i - 1;//质数对应的欧拉函数值为本身减1
        }
        for(int j = 0; primes[j] <= n / i; j ++)
        {
            int t = primes[j] * i;
            st[t] = true;
            if(i % primes[j] == 0)//primes[j]为i的一个质因数,同时也是t的质因数
            {
		//flag1
		euler[t] = euler[i] * primes[j];
                break;
            }
	    //flag2
            euler[t] = euler[i] * (primes[j] - 1);
        }
    }
}

int main()
{
    cin >> n;
    get_eulers(n);
    LL res = 0;
    for (int i = 1; i <= n; i ++ ) res += euler[i];
    cout << res << endl;
    return 0;
}

四、快速幂

正常计算一个数 a a a k k k 次方,则时间复杂度为 O ( k ) O(k) O(k)。而我们换种思路,计算 a a a k k k 次方,我们可以使用 a a a k 2 \frac{k}{2} 2k 自乘计算。那我们就有一种思路 k k k 是偶数 a k = a k 2 × a k 2 a^k=a^\frac{k}{2}\times a^\frac{k}{2} ak=a2k×a2k k k k 是奇数 a k = a k − 1 × a a^k=a^{k-1}\times a ak=ak1×a,特别的 k = 0 k=0 k=0 a k = 1 a^k=1 ak=1。这是一种递归的快速幂。那么我们考虑一下将 k k k 拆解为二进制形式,从低位向高位进行计算,每次移位 a a a 都要自乘,且如果当前为 1 1 1,就要与当前的 a a a 相乘。

模板题AcWing875.快速幂
题目描述

给定 n n n a i , b i , p i a_i,b_i,p_i ai,bi,pi,对于每组数据,求出 a i b i m o d p i a^{b_i}_i mod p_i aibimodpi 的值。

输入格式

第一行包含整数 n n n
接下来 n n n 行,每行包含三个整数 a i , b i , p i a_i,b_i,p_i ai,bi,pi

输出格式

对于每组数据,输出一个结果,表示 a i b i m o d p i a^{b_i}_i mod p_i aibimodpi 的值。
每个结果占一行。

数据范围

1 ≤ n ≤ 100000 , 1≤n≤100000, 1n100000,
1 ≤ a i , b i , p i ≤ 2 × 1 0 9 1≤a_i,b_i,p_i≤2×10^9 1ai,bi,pi2×109

输入样例
2
3 2 5
4 3 9
输出样例
4
1
C++代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

LL qmi(int a, int b, int p)
{
    LL res = 1;
    while(b)
    {
        if(b & 1) res = res * a % p;
        a = (LL) a * a % p;
        b >>= 1;
    }
    return res;
}

int n;

int main()
{
    cin >> n;
    while(n --)
    {
        int a, b, p;
        cin >> a >> b >> p;
        cout << qmi(a, b, p) << endl;
    }
    return 0;
}

四、乘法逆元

若整数 b , m b,m b,m 互质,并且对于任意的整数 a a a,如果满足 b ∣ a b|a ba,则存在一个整数 x x x,使得 a b ≡ a × x ( m o d   m ) \frac{a}{b}\equiv a\times x(mod\,m) baa×x(modm),则称 x x x b b b 的模 m m m 乘法逆元,记为 b − 1 ( m o d   m ) b^{−1}(mod\,m) b1(modm)
b b b 存在乘法逆元的充要条件是 b b b 与模数 m m m 互质。当模数 m m m 为质数时, b m − 2 b^{m−2} bm2 即为 b b b 的乘法逆元(该求法由下面的欧拉定理给出)。

欧拉定理

a a a n n n 互质,则 a ϕ ( n ) ≡ 1 ( m o d   n ) a^{\phi(n)}\equiv 1(mod\,n) aϕ(n)1(modn)。特别地, n n n 为质数时 ϕ ( n ) = n − 1 \phi(n)=n-1 ϕ(n)=n1,故 a n − 1 ≡ 1 ( m o d   n ) a^{n-1}\equiv 1(mod\,n) an11(modn)

模板题AcWing876.快速幂求逆元
题目描述

给定 n n n a i , p i a_i,p_i ai,pi,其中 p i p_i pi 是质数,求 a i a_i ai p i p_i pi 的乘法逆元,若逆元不存在则输出 impossible
注意:请返回在 0 ∼ p − 1 0∼p−1 0p1 之间的逆元。

输入格式

第一行包含整数 n n n
接下来 n n n 行,每行包含一个数组 a i , p i a_i,p_i ai,pi,数据保证 p i p_i pi 是质数。

输出格式

输出共 n n n 行,每组数据输出一个结果,每个结果占一行。
a i a_i ai p i p_i pi 的乘法逆元存在,则输出一个整数,表示逆元,否则输出 impossible

数据范围

1 ≤ n ≤ 1 0 5 , 1≤n≤10^5, 1n105,
1 ≤ a i , p i ≤ 2 × 1 0 9 1≤a_i,p_i≤2\times 10^9 1ai,pi2×109

输入样例
3
4 3
8 5
6 3
输出样例
1
2
impossible
C++代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
typedef long long LL;

LL qmi(int a, int k, int p)
{
    LL res = 1;
    while(k)
    {
        if(k & 1) res = res * a % p;
        a = (LL) a * a % p;
        k >>= 1;
    }
    return res;
}

int n;

int main()
{
    cin >> n;
    while(n --)
    {
        int a, p;
        cin >> a >> p;
        if(a % p == 0) puts("impossible");
        else printf("%lld\n", qmi(a, p - 2, p));
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值