数论日志20201017

gcd & lcm

概念

\(a,b\) 最大的共同的约数叫做 \(a,b\) 的最大公约数。

一般写作 \(\rm gcd(a,b)\)\((a,b)\)

\(a,b\) 最小的共同的倍数数叫做 \(a,b\) 的最小公倍数。

一般写作 \(\rm lcm(a,b)\)\([a,b]\)

性质

\(a,b\) 写成质数乘积的形式,

\(a={p_1}^{c_1} \times {p_2}^{c_2} \times\dots\times {p_k}^{c_k},b= {p_1}^{d_1} \times {p_2}^{d_2} \times\dots\times {p_k}^{d_k}\)

\(\rm gcd(a,b) = {p_1}^{min(c_1,d_1)} \times{p_2}^{min(c_2,d_2)}\times\dots\times {p_k} ^ {min(c_k,d_k)}\)

\(\rm lcm(a,b) = {p_1}^{max(c_1,d_1)} \times{p_2}^{max(c_2,d_2)}\times\dots\times {p_k} ^ {max(c_k,d_k)}\)

\(a\times b=\rm gcd(a,b)\times lcm(a,b)\)

欧几里得算法求最大公约数

\(\gcd(a,b) = \gcd(b,a\bmod b)\)

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

互质

两个数 \(a,b\) 如果 \(\gcd(a,b)=1\),那么 \(a,b\) 互质,记作 \(a\perp b\)

威尔逊定理

一个素数 \(p\),一定满足 \((p-1)!\equiv-1(\bmod p)\)

一个自然数 \(p\),如果满足 \((p-1)!\equiv-1(\bmod p)\),则一定是素数。

费马小定理

内容

一个整数 \(a\) 和一个素数 \(p\),并且 \(a \perp p\),那么 \(a^p \equiv a(\bmod p)\),也可以写成 \(a^{p-1}\equiv 1(\bmod p)\)

降幂

\(a^{p-1} \equiv 1(\bmod p)\)

\(a^{p-1} \equiv a^{(p-1)\bmod (p-1)}(\bmod p)\)

\(a^{x} \equiv a^{x\bmod (p-1)}(\bmod p)\)

费马小定理求逆元

若模数为质数 \(p\),那么根据费马小定理 \(a ^{p-1} \equiv 1(\bmod p)\),那么 \(a ^{p-2} \equiv a^{-1}(\bmod p)\),即 \(a^{p-2}\)\(a\) 在模 \(p\) 意义下的逆元。

欧拉函数

内容

\(\varphi(x)\) 表示的是小于等于 \(x\) 的数中和 \(x\) 互质的数的个数。

\(\varphi(x) = \sum\limits_{i=1}^{x-1} [\gcd(i,x)=1]\),其中方括号是艾佛森括号。

性质

  • 如果 \(p\) 是质数,那么 \(\varphi(p)=p-1\)

  • 欧拉函数是积性函数。

  • \(n\) 为奇数时,\(\varphi(2\times n) = \varphi(n)\)

  • 由唯一分解定理,\(n=\prod_{i=1}^{k}{p_i}^{a_i}\)\(\varphi(n) = \prod_{i=1}^{k}\varphi({p_i}^{a_i})\)

  • \(n=\sum_{d|n} \varphi(d)\)

  • 如果 \(n=p^k\),其中 \(p\) 是质数,那么 \(\varphi(n) = p^k - p^{k-1}\)

  • 由唯一分解定理,\(n=\prod_{i=1}^{k}{p_i}^{a_i}\)\(\varphi(n) = n\times \prod_{i=1}^{k}(1-\dfrac{1}{p_i})=n\times \prod_{i=1}^{k}\dfrac{p_i-1}{p_i}\)

求单个数的欧拉函数

根据欧拉函数的通式:

\(n\) 分解质因数得,\(n={p_1}^{a_1}\times{p_2}^{a_2}\times\dots\times{p_k}^{a_k}\)

\(\varphi(n) = n\times \prod_{i=1}^{k}(1-\dfrac{1}{p_i})=n\times \prod_{i=1}^{k}\dfrac{p_i-1}{p_i}\)

int euler_phi(int n) {
    int m = int(sqrt(n + 0.5));
    int ans = n;
    for (int i = 2; i <= m; i++) {
        if (n % i == 0) {
            ans = ans / i * (i - 1);
            //ans = ans / i * (i - 1) = ans * (i - 1) / i
            //先除再乘是为了防止数太大。
            while (n % i == 0) n /= i;
        }
    }
    if (n > 1) ans = ans / n * (n - 1);
    return ans;
}

线性筛欧拉函数

void phi_table(int n, int* phi) {
    for (int i = 2; i <= n; i++) phi[i] = 0;
    phi[1] = 1;
    for (int i = 2; i <= n; i++)
        if (!phi[i])
            for (int j = i; j <= n; j += i) {
                if (!phi[j]) phi[j] = j;
                phi[j] = phi[j] / i * (i - 1);
            }
}

欧拉定理

如果 \(\gcd(a,n)=1\),则有 \(a^{\varphi(n)}\equiv1(\bmod n)\)

扩展欧拉定理

内容

\[a^b = \begin{cases} a^{b\bmod \varphi(p)} & \gcd(a,p)=1 \\ a^b & \gcd(a,p)\neq1,b<\varphi(p)\\ a^{b\bmod\varphi(p)+\varphi(p)} & \gcd(a,p)\neq1,b\geq\varphi(p)\end{cases}\mod p \]

例题

P4139 上帝与集合的正确用法

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
#define MAXN 10000001
#define int long long

inline void read(int &T) {
    int x=0;bool f=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=!f;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    T=f?-x:x;
}

int t,p,prime[MAXN],phi[MAXN],cnt;
bool vis[MAXN];

inline void count(int n)
{
    for (int i = 2; i <= n; i++)
    {
        if (!vis[i]) phi[i] = i - 1, prime[++cnt] = i;
        for (int j = 1; j <= cnt && i * prime[j] <= n; j++)
        {
            vis[i * prime[j]] = 1;
            if (i % prime[j] == 0)
            {
                phi[i * prime[j]] = phi[i] * prime[j];
                break;
            }
            phi[i * prime[j]] = phi[i] * phi[prime[j]];
        }
    }
}

int qpow(int a,int b,int mod) {
    int ans=1,base=a;
    while(b) {
        if(b&1) ans=(ans*base)%mod;
        base=(base*base)%mod;
        b>>=1;
    }
    return ans%mod;
}

int solve(int now) {
    if(phi[now]==1) return 2;
    return qpow(2,solve(phi[now])+phi[now],now);
}

signed main() {
    count(10000001);
    read(t);
    while(t--) {
        read(p);
        printf("%d\n",solve(p));
    }
}
posted @ 2020-10-17 22:17  yu__xuan  阅读(83)  评论(0编辑  收藏  举报