『笔记』数学数论(八)

[Huge{(八)欧拉定理及其扩展} ]

写在前面

(2021.5.10 quad update) 添加了扩展欧拉定理、部分例题、欧拉群论的证明链接,优化代码模板。

简介

对于任意实数 (n) ,若满足 (gcd(a,n)=1),则有

[a^{varphi(n)} equiv 1 pmod n ]

欧拉函数

定义

欧拉函数 (varphi(n)) 表示在 (1 sim n) 中,于 (n) 互质的数的数量。

已知上述 (a^{varphi(n)} equiv 1 pmod n),若等式两边同除于 (a) ,则有 (a^{varphi(n)-1} equiv cfrac{1}{a} pmod n).

也就是说,在 (pmod n) 意义下,除以 (a) 就相当于乘以 (a^{varphi(n)-1}),而此时的 (varphi(n)) 被称为欧拉函数

例如:(varphi(6) = 2)(varphi(30)=8)

容斥原理求欧拉函数

容斥原理

[S=S_1+S_2+S_3-S_{1,2}-S_{1,3}-S_{2,3}+S_{1,2,3} ]

应用

已知一个整数 (n),它必然可以分解为 (p_1^{r_1}p_2^{r_2}p_3^{r_3}cdots p_k^{r_k}),其中 (p)(n) 的质因子。

那么对于 (n),其中 (p_1) 及其倍数的因子数量即为 (cfrac{n}{p_1})(p_2) 及其倍数的因子数量即为 (cfrac{n}{p_2})(cdots)

显然,(1 sim n) 中与 (n) 不互质的因子的数量即为 (cfrac{n}{p_1}+cfrac{n}{p_2}+cfrac{n}{p_3}+cdots+cfrac{n}{p_k})。相反,与 (n) 互质的因子的数量即 (varphi(n))(n - (cfrac{n}{p_1} + cfrac{n}{p_2} + cfrac{n}{p_3} + cdots + cfrac{n}{p_k}) + NUM - cfrac{n}{p_{1}p_{2}p_{3}cdots p_{k}})

其中 (NUM) 为同时是多个因子的倍数的数的数量。

不难得出,

[egin{aligned} NUM= (cfrac{n}{p_{1}p_{2}} + cfrac{n}{p_{1}p_{3}} + cdots + cfrac{n}{p_{1}p_{k}})&+\ (cfrac{n}{p_{2}p_{1}} + cfrac{n}{p_{2}p_{3}} + cdots + cfrac{n}{p_{2}p_{k}})&+\ cdots &+\ (cfrac{n}{p_{k}p_{2}} + cfrac{n}{p_{k}p_{3}} + cdots + cfrac{n}{p_{k}p_{k-1}}) end{aligned} ]

原式可以因式分解

[egin{aligned} varphi(n) &=n - (cfrac{n}{p_1} + cfrac{n}{p_2} + cfrac{n}{p_3} + cdots + cfrac{n}{p_k}) + NUM - cfrac{n}{p_{1}p_{2}p_{3}cdots p_{k}}\ &=n(1-cfrac{1}{p_1})(1-cfrac{1}{p_2})(1-cfrac{1}{p_3})cdots (1-cfrac{1}{p_k}) end{aligned} ]

代码

int phi(int n) //求 varphi(n)
{
    int res = n;
    for (int i = 2; i <= sqrt(n); i++)
        if (!(n % i))
        {
            res = res / i * (i - 1);
            while (!(n % i))
                n = n / i;
        }
    if (n > 1)
        res = res / n * (n - 1);
    return res;
}

注意

(gcd(a,n) eq 1) 时,(a)(pmod n) 意义下不存在逆元。

也就是说,当 (a,n) 不满足 (a perp n) 时,(a,n) 无法在 (pmod n) 意义下作除法。

欧拉函数表

大多数情况下,欧拉函数是可以直接拿来用的,所以如果遇到此类题目,需要首先预处理欧拉函数表。

const int _ = 1000010;
int varphi[_], prime[_], num, fac[_];
void Phi()
{
    varphi[1] = 1;
    for (int i = 2; i <= n - 1; i++)
    {
        if (!fac[i])
        {
            prime[++num] = i;
            fac[i] = i;
            varphi[i] = i - 1;
        }
        for (int j = 1; j <= num; j++)
            if (prime[j] * i > n || prime[j] > fac[i])
                break;
            else
            {
                fac[prime[j] * i] = prime[j];
                if (prime[j] < fac[i])
                    varphi[prime[j] * i] = prime[j] * varphi[i] - varphi[i];
                else
                    varphi[prime[j] * i] = prime[j] * varphi[i];
            }
        varphi[i] += varphi[i - 1];
    }
}

附:逆元扩展

已知一个质数 (p) ,一个实数 (n),且 (n<p) ,求 (1 sim n)(pmod p) 意义下的逆元。

首先求出 (n!) 的逆元,则 (n) 的逆元为 ((n-1)!cdot (n!)^{-1}),即 (cfrac{(n-1)!}{n!}=cfrac{1}{n})

依此类推,将 ((n!)^{-1}) 乘以 (n),可得到 ([(n-1)!]^{-1}) (cdots)

直到推到 (1)

时间复杂度 (O(n))

YES!

例题

P2158 [SDOI2008]仪仗队

对于此题,非常显然每个点与原点生成的矩形对角线上的所有点,都只能看到第一个。也就是说,对于任意整点 ((x,y)) ,点 ((lambda x,lambda y))((lambda >1)) 都是看不到的。

那么有

[gcd(lambda x,lambda y) = lambda gcd(x,y) >lambda cdot 1 > 1 ]

即对于一个点 ((x,y)) ,若其满足 (gcd(x,y) eq 1) 时,这个点必定看不到。

相反,若其满足 (gcd(x,y)=1) ,且它会被遮挡,则一定存在一个 (mu(mu >1)) 使得 ((cfrac{x}{mu},cfrac{y}{mu})) 能被看到。

又因为 (gcd(x,y)=1),所以 (mu) 一定不存在。

那么可以得出一个结论:一个点 ((x,y)) 能被看到,当且仅当 (gcd(x,y)=1)

(n=1) 时,答案为 (0)

否则,答案为 (sum limits_{x=0}^{n-1} sum limits_{y=0}^{n-1}[gcd(x, y)=1], n geq 2)

展开

[egin{aligned} sum limits_{x=0}^{n-1} sum limits_{y=0}^{n-1}[gcd(x, y)=1] = sum_{x=0}^{n-1} sum_{y=0}^{x-1}[gcd(x, y)=1]&+\ sum_{x=0}^{n-1} sum_{y=x}^{x}[gcd(x, y)=1] &+\ sum_{x=0}^{n-1} sum_{y=x+1}^{n-1}[gcd(x, y)=1]&, end{aligned} ]

其中 (n geq 2)

根据

[sum limits_{x=0}^{n-1} sum limits_{y=0}^{x-1}[gcd(x, y)=1]=sum limits_{x=0}^{n-1} sum_{y=x+1}^{n-1}[gcd(x, y)=1] ]

[ ext{原式}= 2 sum limits_{x=0}^{n-1} sum limits_{y=0}^{x-1}[g c d(x, y)=1]+1 ]

其中 (n geq 2)

引入欧拉函数 (varphi(n))

[varphi(n)=sum limits_{i=0}^{n-1}[gcd(i, n)=1] ]

[ ext{ans}(n)=2 sum limits_{x=0}^{n-1} varphi(x)+1 ]

其中 (n geq 2)

综上所述,

[ans= left{ egin{array}{l} 0 & n=1 \ 2 sum limits_{x=0}^{n-1} varphi(x)+1 & n geq 2 end{array} ight. ]

/*

Name: P2158 [SDOI2008]仪仗队

Solution: 欧拉函数
   

By Frather_

*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define int long long
#define InF 0x3f3f3f3f
#define kMax 10e5
#define kMin -10e5
#define kMod 998244353
using namespace std;
/*==================================================快读*/
inline int read()
{
    int X = 0, F = 1;
    char CH = getchar();
    while (CH < '0' || CH > '9')
    {
        if (CH == '-')
            F = -1;
        CH = getchar();
    }
    while (CH >= '0' && CH <= '9')
    {
        X = (X << 3) + (X << 1) + (CH ^ 48);
        CH = getchar();
    }
    return X * F;
}
/*===============================================定义变量*/
int n;

const int _ = 1000010;
int phi[_], prime[_], num, fac[_];
/*=============================================自定义函数*/
void Phi()
{
    phi[1] = 1;
    for (int i = 2; i <= n - 1; i++)
    {
        if (!fac[i])
        {
            prime[++num] = i;
            fac[i] = i;
            phi[i] = i - 1;
        }
        for (int j = 1; j <= num; j++)
            if (prime[j] * i > n || prime[j] > fac[i])
                break;
            else
            {
                fac[prime[j] * i] = prime[j];
                if (prime[j] < fac[i])
                    phi[prime[j] * i] = prime[j] * phi[i] - phi[i];
                else
                    phi[prime[j] * i] = prime[j] * phi[i];
            }
        phi[i] += phi[i - 1];
    }
}
/*=================================================主函数*/
signed main()
{
    n = read();
    Phi();
    printf("%lld
", n == 1 ? 0 : 2 * phi[n - 1] + 1);
    return 0;
}

扩展欧拉定理

我们已知,只有当 (a,n) 满足 (gcd(a,n)=1) 时,欧拉定理才成立,那么若 (a,b) 不互质呢?

定义

对于 (a,n)(gcd(a,n) eq 1) ,时,有

[a^c equiv left{ egin{array}{ll} a^{c mod{varphi(n)} } & gcd(a,n) = 1 \ a^c & gcd(a,n) eq 1 ext{且} c < varphi(n) \ a^{c mod{varphi(n) + varphi(n)} } & gcd(a,n) eq 1 ext{且} c geq varphi(n) end{array} ight. ]

证明

不妨首先考虑一个质因子 (p),令 (n=s cdot p^r ,gcd(s,p)=1)

(p^{varphi(s)} equiv 1 pmod s) , 又由 (gcd(s,p)=1) ,则有 (varphi(s) mid varphi(n)),即 (p^{varphi(n)} equiv 1 pmod s)

根据同余式性质,两边同时乘以一个 (p^r)

[p^{varphi(n)+r} equiv p^r pmod n ]

那么有

[p^c equiv p^{c-r+r} equiv p^{varphi(n) + c} pmod n ]

其中 (c geq r)

显然, (r leq varphi(n))

因此

[p^r equiv p^{varphi(n)+c} pmod n ]

其中 (c geq varphi(n))

上式可转化为

[p^c equiv p^{c mod{varphi(n)} + varphi(n)} pmod n ]

其中 (c geq varphi(n))

类似的,可以有

[egin{aligned} (p^k)^c &= p^{kc} \ &equiv p^{varphi(n) + kc} \ &equiv p^{k varphi(n) + kc} = (p^k)^{varphi(n) + c} \ &equiv (p^k)^{c mod varphi(n) + varphi(n)} end{aligned} pmod n ]

其中 (c geq varphi(n),k>0)

由于 (p)(a) 的因子,即 (a = prod p_{i}^{k_{i}}) ,而对于每一个 (p) 都满足上述证明,那么其乘积也必然满足,所以有

[a^c equiv a^{c mod varphi(n) + varphi(n)} pmod n ]

其中 (c geq varphi(n))

证毕。

例题

P5091 【模板】扩展欧拉定理

RT,模板题。

/*

Name: P5091 【模板】扩展欧拉定理

Solution: 扩展欧拉定理
   

By Frather_

*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define int long long
#define InF 0x3f3f3f3f
#define kMax 10e5
#define kMin -10e5
#define kMod 998244353
using namespace std;
/*==================================================快读*/
inline int read()
{
    int X = 0, F = 1;
    char CH = getchar();
    while (CH < '0' || CH > '9')
    {
        if (CH == '-')
            F = -1;
        CH = getchar();
    }
    while (CH >= '0' && CH <= '9')
    {
        X = (X << 3) + (X << 1) + (CH ^ 48);
        CH = getchar();
    }
    return X * F;
}
/*===============================================定义变量*/
int a, m, b;
/*=============================================自定义函数*/
inline int read_(int kmod)
{
    int X = 0;
    bool F = false;
    char CH = getchar();
    while (CH < '0' || CH > '9')
        CH = getchar();
    while (CH >= '0' && CH <= '9')
    {
        X = (X << 3) + (X << 1) + (CH ^ 48);
        if (X >= kmod)
            F = true;
        X %= kmod;
        CH = getchar();
    }
    return X + (F ? kmod : 0);
}

int phi(int n) //求 varphi(n)
{
    int res = n;
    for (int i = 2; i <= sqrt(n); i++)
        if (!(n % i))
        {
            res = res / i * (i - 1);
            while (!(n % i))
                n = n / i;
        }
    if (n > 1)
        res = res / n * (n - 1);
    return res;
}

int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}

int Qpow(int a, int t, int p)
{
    int res = 1;
    while (t)
    {
        if (t & 1)
            res = res * a % p;
        a = a * a % p;
        t >>= 1;
    }
    return res;
}
/*=================================================主函数*/
signed main()
{
    a = read();
    m = read();
    int t = phi(m);
    b = read_(t);
    int g = gcd(a, m);
    // if (g = 1)
    //     printf("%lld
", Qpow(a, b % t, m));
    // else if (g != 1 && b < t)
        printf("%lld
", Qpow(a, b, m));
    // else if (g != 1 && b >= t)
    //     printf("%lld
", Qpow(a, b % t + t, m));
    return 0;
}

欧拉定理的群论证明

详情可参见这篇博客

原文地址:https://www.cnblogs.com/Frather/p/14734191.html