欧拉函数+快速幂+扩欧+中国剩余定理

欧拉函数+快速幂+扩欧+中国剩余定理

欧拉函数

公式法

\[1-N中与N互质的数的个数被称为欧拉函数,记为\phi(N)\\ 在算术基本定理中,N=P_1^{\alpha_1}P_2^{\alpha_2}...P_m^{\alpha_m},则:\\ \phi(N)=N*\frac{p_1-1}{p_1}*\frac{p_2-1}{p_2}*...*\frac{p_m-1}{p_m\\} \]

\[1,2,3,4,5,6\\ 与6互质的数有:1,5\\ 6=2^1\times3^1\\ \phi(6)=6\times\frac{2-1}{2}\times\frac{3-1}{3}=2\\ \]

\[证明如下:(容斥原理)\\ 1.从1-N中去除p_1,p_2,...,p_k的所有倍数\\ N-\frac{N}{p_1}-\frac{N}{p_2}-...-\frac{N}{p_k}\\ 2.加上所有p_i*p_j的倍数\\ N-\frac{N}{p_1}-\frac{N}{p_2}-...-\frac{N}{p_k}+\frac{N}{p_1p_2}+\frac{N}{p_1p_3}+\frac{N}{p_{k-1}p_k}\\ 3.减去所有p_i*p_j*p_k的倍数\\ N-\frac{N}{p_1}-\frac{N}{p_2}-...-\frac{N}{p_k}+\frac{N}{p_1p_2}+\frac{N}{p_1p_3}+\frac{N}{p_{k-1}p_k}-\frac{N}{p_1p_2p_3}-...-\frac{N}{p_{k-2}p_{k-1}p_{k}}\\ N-\frac{N}{p_1}-\frac{N}{p_2}-...-\frac{N}{p_k}+\frac{N}{p_1p_2}+\frac{N}{p_1p_3}+\frac{N}{p_{k-1}p_k}+...+(-1)^k\frac{N}{p_1...p_k}=N*\frac{p_1-1}{p_1}*\frac{p_2-1}{p_2}*...*\frac{p_m-1}{p_m\\}=\phi(N)\\ \]

求欧拉函数算法模板

\(O(\sqrt{n})\)

int phi(int x)
{
    int res = x;
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0)
        {
            res = res / i * (i - 1);
            while (x % i == 0) x /= i;
        }
    if (x > 1) res = res / x * (x - 1);

    return res;
}

筛法

求1-N每个数的欧拉函数

\[i = p_1^{\alpha_1} ...p_k^{\alpha_k}\\ primes[j] * i = primes[j]*p_1^{\alpha_1} ...p_k^{\alpha_k}\\ \\ 若p为质数,那么1-p中有p-1个数和p互质\\ \\ 假如i\%primes[j]==0\\ 则primes[j]是i的最小质因子\\ \therefore primes[j] = p_1\\ \therefore primes[j] * i = p_1^{\alpha_1+1} ...p_k^{\alpha_k}\\ \phi(i)=i*(\frac{p_1-1}{p_1})*(\frac{p_2-1}{p_2})*...*(\frac{p_k-1}{p_k})\\ \phi(primes[j] * i)=primes[j] * i*(\frac{p_1-1}{p_1})*(\frac{p_2-1}{p_2})*...*(\frac{p_k-1}{p_k})=primes[j]*\phi(i)\\ \therefore \phi(primes[j] * i)=primes[j]*\phi(i)\\ \\ 假如i\%primes[j]!=0\\ 那么primes[j]一定是primes[j]*i的最小质因子,并且primes[j]不存在于i的质因子当中\\ \phi(i)=i*(\frac{p_1-1}{p_1})*(\frac{p_2-1}{p_2})*...*(\frac{p_k-1}{p_k})\\ \phi(primes[j]*i)=primes[j]*i*(\frac{p_1-1}{p_1})*...*(\frac{p_k-1}{p_k})*(\frac{primes[j]-1}{primes[j]})=primes[j]*\frac{primes[j]-1}{primes[j]}*\phi(i)\\ \therefore \phi(primes[j]*i)=(primes[j]-1)*\phi(i)\\ \]

筛法求欧拉函数算法模板

int primes[N], cnt;     // primes[]存储所有素数
int euler[N];           // 存储每个数的欧拉函数
bool st[N];         // st[x]存储x是否被筛掉


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

欧拉定理

\[若a与n互质,则a^{\phi(n)} \equiv 1 (mod \; n)\\ 特别地,当n为质数时,a^{n-1} \equiv 1 (mod \; n) \quad (费马定理)\\ \]

\[证明如下:\\ 1-n中,与n互质的数为:a_1,a_2,...,a_{\phi(n)}\\ 又\because a与n互质\\ \therefore aa_1,aa_2,...,aa_{\phi(n)}也与n互质\\ \\ 已知a*a_i与n互质,要证(a*a_i)\%n与n互质\\ 设c=(a*a_i)\%n\\ 假设c与n不互质\\ 则存在d>1,s.t.c=kd,n=jd\\ \because c=(a*a_i)\%n\\ \therefore a*a_i=fn+c=fjd+kd= (fj+k)d\\ \because n=jd\\ \therefore a*a_i与n不互质,假设不成立\\ \therefore (a*a_i)\%n与n互质\\ \\ \because (a*a_i)\%n<n\\ 又\because 1-n中,与n互质的数为:a_1,a_2,...,a_{\phi(n)}\\ \therefore (a*a_i)\%n \in \{a_1,a_2,...,a_{\phi(n)}\}\\ \because (a\times b)\%n=(a\%n)\times (b\%n)且aa_1,aa_2,...,aa_{\phi(n)}互不相同\\ \therefore (aa_1\times aa_2\times ...\times aa_{\phi(n)})\%n=a_1\times a_2\times ...\times a_{\phi(n)}\\ \therefore a^{\phi(n)}\times a_1\times a_2\times ...\times a_{\phi(n)}= a_1\times a_2\times ...\times a_{\phi(n)} \; (mod \; n)\\ a^{\phi(n)} \equiv 1 (mod \; n)\\ \]

快速幂

快速求出\(a^k \; mod\; p\)

O(log k)

\[a^k \; mod\; p\\ 预处理出\; a^{2^0} \; mod \; p,....,a^{2^{log\;k}}\;mod\;p这log\;k个数\\ a^k=a^{2^{x_1}}a^{2^{x_2}}...a^{2^{x_t}}=a^{2^{x_1}+2^{x_2}+...+2^{x_t}}\\ k=2^{x_1}+2^{x_2}+...+2^{x_t}\\ (101011)_2=2^0+2^1+2^3+2^5\\ \\ 预处理:\\ a^{2^0}=a\\ a^{2^1}=(a^{2^0})^2\\ ...\\ a^{2^{log\;k}}=(a^{2^{log\;k-1}})^2\\ 每个数是前面的数的平方,预处理出log\;k个数,复杂度O(log\;k) \]

\[(5)_{10}=(101)_2\\ 4^5\;mod\;10\\ 4^{2^0}\;mod\;10\equiv 4\;mod\;10\\ 4^{2^1}\;mod\;10\equiv 6\;mod\;10\\ 4^{2^2}\;mod\;10\equiv 6\;mod\;10\\ 4^5=4^{2^0}4^{2^2}=4*6=4\;mod\;10 \]

快速幂算法模板

// 求 m^k mod p,时间复杂度 O(logk)。

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

快速幂求逆元

乘法逆元:

若整数\(b,m\)互质,并且对于任意的整数\(a\),如果满足\(b|a\),则存在一个整数\(x\),使得\(a/b\equiv a\times x\;(mod\;m)\),则称\(x\)\(b\)的模\(m\)乘法逆元,记为 \(b^{−1}\;(mod\;m)\)
\(b\)存在乘法逆元的充要条件是\(b\)与模数\(m\)互质。当模数\(m\)为质数时,\(b^{m−2}\)即为 b的乘法逆元。

\[\frac{a}{b}\equiv ax\;mod\;m\\ \frac{a}{b}\equiv ab^{-1}\;mod\;m\\ bx\equiv 1(mod \;p)\\ 若b、p互质且p为质数,则由费马定理,有b^{p-1}\equiv1(mod\;p)\\ bb^{p-2}\equiv1(mod\;p)\\ \therefore b^{p-2}为b的乘法逆元\\ !!!充要条件:b与p互质且p为质数\\ \]

扩展欧几里得

\[裴蜀定理\\ 对任意正整数a,b,一定存在非零整数x,y,使得ax+by=gcd(a,b)\\ 当b=0时,ax+by=a,易得x=1,y可以取任意实数\\ 当b!=0时,ax+by=gcd(a,b)=gcd(b,a\;mod\;b)\\ bx'+(a\;mod\;b)y'=gcd(b,a\;mod\;b)\\ bx'+(a-\lfloor\frac{a}{b}\rfloor b)y'=gcd(a,b)\\ ay'+b(x'-\lfloor\frac{a}{b}\rfloor y')=ax+by\\ 互换x'、y'\\ ax'+b(y'-\lfloor\frac{a}{b}\rfloor x')=ax+by\\ x=x',y=y'-\lfloor\frac{a}{b}\rfloor x'\\ \\ ax+by=(a,b)\\ ax+by=d有解当且仅当d=k(a,b)\\ \]

扩展欧几里得算法模板

// 求x, y,使得ax + by = gcd(a, b)
int exgcd(int a, int b, int &x, int &y)
{
    if (!b)
    {
        x = 1; y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= (a/b) * x;
    return d;
}

求解线性同余方程

\[ax\equiv b(mod \; m)\\ ax=my+b\\ ax-my=b\\ ax+my=b\\ 当b为gcd(a,m)的倍数时有解,x = (long \;long)x\times b / gcd(a,m) \% m\\ \]

中国剩余定理

\[给定一堆两两互质的数m_1,m_2,...,m_k,有线性同余方程组\\ \begin{cases} \ x\equiv a_1(mod\;m_1) \\ \ x\equiv a_2(mod\;m_2) \\ \ ...... \\ \ x\equiv a_k(mod\;m_k) \\ \end{cases} \\ 令M=m_1m_2...m_k\\ M_i=\frac{M}{m_i}(因为m_i两两互质,所以M_i与除了m_i以外的其他m互质)\\ M_i^{-1}表示M_i模m_i的逆(用扩欧来求解)\\ M_ix\equiv1(mod\;m_i) \Rightarrow M_ix+km_i=1\\ 中国剩余定理:x=a_1\times M_1\times M_1^{-1}+a_2\times M_2\times M_2^{-1} + ...+a_k\times M_k\times M_k^{-1} \]

#include <iostream>

using namespace std;

typedef long long ll;
const int N = 15;

ll a[N], m[N];
ll M = 1, res;

ll exgcd(ll a, ll b, ll &x, ll &y)
{
    if(!b)
    {
        x = 1, y = 0;
        return a;
    }
    ll d = exgcd(b, a % b, y, x);
    y -= (a / b) * x;
    return d;
}

int main()
{
    int n;
    cin >> n;
    for(int i = 1; i <= n; i ++)
    {
        cin >> m[i] >> a[i];
        M *= m[i];
    }
    for(int i = 1; i <= n; i ++)
    {
        ll Mi = M / m[i], x, k, d;
        d = exgcd(Mi, m[i], x, k);
        x %= m[i];
        res = (res + a[i] * Mi * x) % M;
    }
    cout << (res % M + M) % M << endl;
    return 0;
}

拓展中国剩余定理

不满足两两互质条件时

给定\(2n\)个整数\(a_1,a_2,...,a_n\)\(m_1,m_2,...,m_n\),求一个最小的非负整数x,满足\(\forall i \in[1,n],x\equiv m_i(mod\;a_i)\)

\[\begin{cases} \ x\equiv m_1(mod\;a_1) \\ \ x\equiv m_2(mod\;a_2) \\ \ ...... \\ \ x\equiv m_n(mod\;a_n) \\ \end{cases} \\ \Rightarrow \begin{cases} \ x\;mod\;a_1=m_1 \\ \ x\;mod\;a_2=m_2 \\ \ ...... \\ \ x\;mod\;a_n=m_n \\ \end{cases} \]

\[对于每两个式子(我们考虑将其合并):\\ \begin{cases} \ x\;mod\;a_1=m_1\\ \ x\;mod\;a_2=m_2\\ \end{cases} \\ \Rightarrow \begin{cases} \ x = k_1a_1+m_1\\ \ x = k_2a_2+m_2\\ \end{cases} \\ \Rightarrow k_1a_1+m_1 = k_2a_2+m_2\\ \Rightarrow k_1a_1-k_2a_2=m_2-m_1\\ \Rightarrow k_1a_1+k_2a_2=m_2-m_1\\ \because a_1、a_2、m_1、m_2已知\\ \therefore k_1a_1+k_2a_2=gcd(a_1,a_2),可求出k_1,k_2\\ k_1a_1+k_2a_2=m_2-m_1有解当且仅当gcd(a1,a2) | m2-m1\\ 让k_1,k_2扩大\frac{m_2-m_1}{gcd(a_1,a_2)}倍,得到k_1a_1+k_2a_2=m_2-m_1的一组解\\ \begin{cases} \ k1=k1+k\frac{a_2}{d}(k_1\in Z)\\ \ k2=k2+k\frac{a_a}{d}(k_2\in Z)\\ \end{cases} \\ 此时,新的k_1,k_2仍满足原式\\ 但为了避免溢出,通常取k1为满足条件的最小的正整数\\ \therefore k_1=k_1\%\frac{a_2}{d},k_2=k2\%\frac{a_1}{d}\\ \therefore x=k_1a_1+m_1=(k1+k\frac{a_2}{d})a_1+m_1=a_1k_1+m_1+k\frac{a_1a_2}{d} =a_1k_1+m_1+k*lcm(a_1,a_2)\\ 令m_0=a_1k_1+m_1,a_0=lcm(a_1,a_2)\\ 则x=m_0+ka_0 \]

#include <iostream>

using namespace std;

typedef long long ll;

ll exgcd(ll a, ll b, ll &x, ll &y)
{
    if (!b)
    {
        x = 1, y = 0;
        return a;
    }
    ll d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

int main()
{
    int n;
    cin >> n;
    ll a1, m1;
    cin >> a1 >> m1;
    for (int i = 0; i < n - 1; i ++ )
    {
        ll a2, m2, k1, k2;
        cin >> a2 >> m2;
        ll d = exgcd(a1, a2, k1, k2);
        if ((m2 - m1) % d)
        {
            cout << "-1" << endl;
            return 0;
        }

        k1 *= (m2 - m1) / d;
        k1 = (k1 % (a2/d) + a2/d) % (a2/d);

        m1 = k1 * a1 + m1;
        a1 = a1 / d * a2;
    }
    ll x = (m1 % a1 + a1) % a1;
    cout << x << endl;
    return 0;
}
posted @ 2022-12-23 22:57  钰见梵星  阅读(41)  评论(0编辑  收藏  举报