整除与同余

整除和同余理论

同余方程

定义:形如 \(ax \equiv c\ (\text{mod}\ b) \Longleftrightarrow ax+by=c\) 的方程。

裴蜀定理

内容:\(a,b\) 为正整数,则 \(ax+by=c\) 有整数解当且仅当 \(\gcd(a,b)\)\(c\) 的因数。

exgcd(扩展欧几里得算法)

扩展欧几里得算法(exgcd)——可求解 \(\gcd\),解同余方程、乘法逆元。

\[ax+by=c \\ \Rightarrow ax+by=\gcd(a,b)\\ \Rightarrow bx_0+a\text{ mod }b y_0=\gcd(a,b) \]

内容:对于形如 \(ax+by=\gcd(a,b)\) 的方程,当 \(b=0\) 时,\(x=1,y=0\) 是方程的一组特解。

\[bx_0 + (a-\lfloor\dfrac{a}{b}\rfloor b)y_0=\gcd(a,b)\\ \Rightarrow ay_0 + (x_0 - \lfloor\dfrac{a}{b}\rfloor y_0)b=\gcd(a,b)\\ \Rightarrow x=y_0 , y=x_0-\lfloor\dfrac{a}{b}\rfloor y_0 \]

模板
inline int exgcd(int a,int b,int &x,int &y)
{
    int d=a;
    if(b==0) x=1,y=0;
    else d=exgcd(b,a%b,y,x),y-=(a/b)*x;
    return d;
}

乘法逆元

定义:\(ax \equiv 1(\text{mod }p)\),就称 \(a\)\(x\) 在模 \(p\) 意义下互为乘法逆元。

例:

若要求 \((\dfrac{m}{n})\text{ mod }p\),则转化为 \((m\times inv_n)\text{ mod }p\),其中 \(inv_n\) 表示模 \(p\) 意义下 \(n\) 的逆元。

标准分解式

定义:将质因数分解的结果,按照质因数大小,由小到大排列,并将相同质因数的连乘积,以指数形式表示。

例:

\(2020\) 的标准分解式为 \(2^2 \times 55\times 101\)

欧拉函数

定义:\(\varphi(n)\) 指在小于 \(n\) 的正整数中与 \(n\) 互质的数的个数。

求法:

1.先化为标准分解式:

\[n=p_1^{k_1}p_2^{k_2}...p_L^{k_L} \]

2.再根据公式计算:

\[\varphi(n) = \prod\limits^r_{i=1}p_i^{k_i-1}(p_i-1)\\ =\prod\limits_{p|n}p^{\alpha_p-1}(p-1)\\ =n\prod\limits_{p|n}(1-\dfrac{1}{p}) \]

但当 \(m\) 为合数时,且不知道 \(m\) 的因数分解式时,通常很难求出 \(n\) 的欧拉函数值 \(\varphi(m)\)

欧拉函数线性筛法,时间复杂度 \(O(n)\)

模板
const int MAXN=4e4+5;

int phi[MAXN],prime[MAXN],m,ans;
bool vis[MAXN];

inline void getphi()
{
    phi[1]=1;
    for(int i=2;i<=MAXN;i++)
    {
        if(!vis[i])
            prime[++m]=i,phi[i]=i-1;
        for(int j=1;j<=m;j++)
        {
            if(i*prime[j]>MAXN) break;
            vis[i*prime[j]]=true;
            if(!(i%prime[j]))
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            else phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
}

欧拉定理

内容:对于两个正整数 \(a,n\),若 \(a,n\) 互质,则

\[a^{\varphi(n)}\equiv1\ (\text{mod}\ n) \]

一般常用到它的推论:对于两个正整数 \(a,n\),若 \(a,n\) 互质,则

\[a^b\equiv a^{b\text{ mod } \varphi(n)}\ (\text{mod }n) \]

利用这个推论,在满足 \(a,m\) 互质的前提下,即使 \(b\) 较大,我们也可以轻松地计算 \(a^b\text{ mod }m\) 的值。

扩展欧拉定理

通常用来解决欧拉定理的推论中 \(a,m\) 不互质时的情况。

内容:

\[a^b\equiv\begin{cases}a^b\ (\text{mod }n)&(b<\varphi(n))\\ a^{b\text{ mod }\varphi(n)+\varphi(n)}\ (\text{mod }n)&(b\geqslant \varphi(n))\end{cases} \]

费马小定理

定义:\(p\) 是一个素数,则对于任意整数 \(a\),有

\[a^p \equiv a\ (\text{mod}\ p) \Longleftrightarrow a^{p-1}\equiv 1\ (\text{mod}\ p) \]

同样可以用来求逆元。

威尔逊定理

定义:对于一个素数 \(p\),有

\[(p-1)!\equiv -1\ (\text{mod}\ p) \]

BSGS(大步小步算法)

通常用来求解离散对数问题,即求解形如 \(a^x \equiv b\ (\text{mod }p)\) 的方程的解。

内容:

\(k=\lceil\sqrt{p}\rceil\),令 \(x=ky+z\),则

\[a^x=a^{ky+z}\equiv b\ (\text{mod }p)\Longleftrightarrow a^{ky}\equiv \dfrac{b}{a^z}\ (\text{mod }p) \]

预处理出所有 \(\dfrac{b}{a^z}\) 并哈希存储,枚举 \(y\) 后判断是否有满足条件的即可。

模板
inline int BSGS(int a,int b,int MOD)
{
    map<int,int>ma;
    int cur=1,t=sqrt(MOD)+1;
    for(int i=1;i<=t;i++)
    {
        cur=cur*a%MOD;
        ma[b*cur%MOD]=i;
    }
    int now=cur;
    for(int i=1;i<=t;i++)
    {
        if(ma[now]) return i*t-ma[now];
        now=now*cur%MOD; 
    }
    return -1;
}

CRT(中国剩余定理)

通常用来求解形如

\[\begin{cases}x\equiv a_1\ (\text{mod }p_1)\\x\equiv a_2\ (\text{mod }p_2)\\...\\x\equiv a_n\ (\text{mod }p_n)\end{cases} \]

的同余方程的解,其中 \(p_1,p_2,...,p_n\) 均为质数。

内容:

\(M=\prod p_i,m_i=\dfrac{M}{p_i},t_i\equiv \dfrac{1}{m_i}\ (\text{mod }p)_i\)

那么我们可以发现 \(a_it_im_i\equiv 0\ (\text{mod }m_i),a_it_im_i\equiv a_i\ (\text{mod }p_i)\)

于是答案便为 \(\sum a_it_im_i\ (\text{mod }M)\)

有时需要用到龟乘

模板
inline int exgcd(int a,int b,int &x,int &y)
{
    int d=a;
    if(b==0) x=1,y=0;
    else d=exgcd(b,a%b,y,x),y-=(a/b)*x;
    return d;
}

int a[MAXN],b[MAXN],n;

inline int CRT(int mod)
{
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        int M=mod/a[i];
        int x,y;
        int d=exgcd(M,a[i],x,y);
        ans=((ans+x*M*b[i])%mod+mod)%mod;
    }
    return ans;
}

exCRT(扩展中国剩余定理)

内容:

对于上面的方程,假设合并两个方程:

\[\begin{cases}x\equiv a_1\ (\text{mod }p_1)\\x\equiv a_2\ (\text{mod }p_2)\end{cases} \]

那么合并出来的模数一定是 \(\text{lcm}(p_1,p_2)\)

于是有:\(x=k_1p_1+a_1=k_2p_2+a_2\).

\(\text{exgcd}\) 求出 \(k_1,k_2\) 即可。

其中无解的情况就是 \(\text{exgcd}\) 无解的情况。

模板
int n,a[MAXN],b[MAXN];

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

inline int gcd(int a,int b)
{
    if(b==0) return a;
    else return gcd(b,a%b);
}

inline int lcm(int a,int b)
{
    return a/gcd(a,b)*b;
}

inline int Mod(int x,int p)
{
    return (x%p+p)%p;
}

int x0,y0;

inline int exCRT(int A,int B)
{
    for(int i=2;i<=n;i++)
    {
        int g=Mod(b[i]-B,a[i]),d=exgcd(A,a[i],x0,y0);
        if(g%d) printf("No Solution\n");
        x0*=g/d,x0%=a[i]/d;
        B+=A*x0,A=lcm(A,a[i]),B=Mod(B,A);
    }
    return B;
}

posted @ 2022-10-16 08:30  Code_AC  阅读(105)  评论(0编辑  收藏  举报