首页 > 其他分享 >数论从入门到进门

数论从入门到进门

时间:2024-02-16 12:33:54浏览次数:36  
标签:入门 数论 bmod varphi cdot int pmod 进门 equiv

gcd

朴素欧几里得(辗转相除法)

  • 这一节我们默认:\(a,b\in\mathbb{Z}\)

对于求解 \(\gcd(a,b)\) 需要用朴素欧几里得定理。

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


gcd

  • \(\gcd\) 为 \(\text{greatest common divisor}\) 的缩写,即最大公约数。(或称最大公因数)

  • 对于 \(\gcd\) 函数,有以下几个性质:

  1. \(\gcd(a,b)=\gcd(b,a)\)
  2. \(\gcd(a,-b)=\gcd(a,b)\)
  3. \(\gcd(a,a)=|a|\)
  4. \(\gcd(a,0)=|a|\)
  5. \(\gcd(a,1)=1\)
  6. 若有常数 \(k\in \mathbb{Z}\),则:

\(\gcd(ka,kb)=k\times\gcd(a,b)\)

\(\gcd(a+kb,b)=\gcd(a,b)\)


对于定理的证明:

令 \(c=\gcd(a,b)\),则存在 \(a=mc,b=nc\)。

令 \(r=a\bmod b\),则存在\(k\),使\(r=a-kb=mc-knc=c\times(m-kn)\)。

\(\therefore \gcd(b,a\bmod b)=\gcd(b,r)=\gcd(nc,c\times(m-kn))=c\times gcd(n,m-kn)\)。

\(\therefore c\) 为 \(a\) 和 \(b\) 的公约数。

令 \(d=\gcd(n,m-kn)\),则存在 \(x,y\) 使 \(n=xd,m-kn=yd\)

\(\therefore m=yd+kn=yd+kxd=d\times (y+kx)\)

\(\therefore a=mc=d\times(y+kx)c=dc\times(y+kx)\),\(b=nc=xdc=dc\times x\)

\(\therefore \gcd(a,b)=\gcd(\red{dc}\times(y+kx),\red{dc}\times x)=\red{dc}\)

\(\because \gcd(a,b)=c\)

联立得:\(dc=c\)

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

联立得:\(\gcd(a,b)=c=\gcd(b,a\bmod b)\)


  • 代码实现:

有两种写法,个人推荐第一种。时间复杂度为 \(O(\log n)\)。

inline int gcd(int a,int b){
    int temp;
    while(b){//边界条件为b=0;
        temp=b;
        b=a%b;
        a=temp;
    }
    return a;
}
inline int gcd(int a,int b){return b?gcd(b,a%b):a;}

扩展欧几里得(exgcd)

  • 对于三个整数 \(a,b,c\),求解 \(ax+by=c\) 的整数解。

首先要判断是否有解,有解的充分条件是 \(\gcd(a,b)\mid c\)(裴蜀定理)。

然后判定是否有解后,我们需要在这个基础上求一组解 \((x,y)\)

若 \(a<0\) 或 \(b<0\) 用上述的性质化为正数即可。

先将式子两边同除 \(\gcd(a,b)\),所以式子转化为了:

\(ax+by=1(a\bot b)\)

用前面的朴素欧几里得推式子:

\[\begin{aligned}ax+by&=\gcd(a,b)\\&=\gcd(b,a\bmod b)\\&=bx+(a\bmod b)y\\&=bx+(a-\left\lfloor\dfrac{a}{b}\right\rfloor b)y\\&=ay+b(x-\left\lfloor\dfrac{a}{b}\right\rfloor y)\end{aligned} \]

此时 \(x\Leftarrow y,y\Leftarrow ay+b(x-\left\lfloor\dfrac{a}{b}\right\rfloor y)\)。

所以可以递归求解。

边界条件和朴素欧几里得一样,当 \(b=0\) 时,有 \(a=1\) 且 \(ax+by=1\),所以 \(x=1,y=0\)。

这样做完的话我们用 \(O(\log n)\) 的时间就会得到一组 \((x,y)\) 的特殊解。


不定方程通解公式

有方程 \(ax+by=c\) 且已知 \(x=x_0,y=y_0\)。

\(\therefore a(x-x_0)+b(y-y_0)=0\)

\(\therefore a(x-x_0)=b(y_0-y)\)

设 \(a\bot b\),则 \(x-x_0\) 必含因子 \(b\),\(y_0-y\) 必含因子 \(a\)

\(\therefore x-x_0=kb,y_0-y=ka(k\in \mathbb Z)\)

\(\therefore \begin{cases}x=x_0+kb\\y=y_0-ka\end{cases}(k\in \mathbb Z)\)


解系拓展

有时题目要求的不是 \((x,y)\) 这一解,而是某种特殊解,这时需将其拓展成解系。

根据不定方程通解公式可得:

\[\begin{cases}x=x_0+kb\\y=y_0-ka\end{cases}(k\in \mathbb Z) \]

然后根据题面找出特殊解即可。

  • 注意:
  1. 最后都要乘\(c\)。

  2. 记得令 \(x=(x\bmod b+b)\bmod b\) 就行了。防止爆 \(\text {int}\) 或其他玄学错误

  • 代码实现
inline void Exgcd(int a,int b,int &x,int &y){
		if(b)Exgcd(b,a%b,y,x),y-=a/b*x;//同样的递归条件
		else x=1,y=0;
}

调用的话,\(x=y',y=x'\),只修改 \(y\) 的值。


更相减损术

  • 更相减损术是出自《九章算术》的一种求最大公约数的算法,它原本是为约分而设计的,但它适用于任何需要求最大公约数的场合。

原文:
可半者半之,不可半者,副置分母、子之数,以少减多,更相减损,求其等也。以等数约之。

译文(来自百度):(如果需要对分数进行约分,那么)可以折半的话,就折半(也就是用2来约分)。如果不可以折半的话,那么就比较分母和分子的大小,用大数减去小数,互相减来减去,一直到减数与差相等为止,用这个相等的数字来约分。

  • 代码实现:
inline int gcd(int a,int b){
		while(a!=b)
			a>b?a-=b:b-=a;
		return a;
}

时间复杂度为 \(O(\log n)\),但是如果遇到一个数很大,另一个数比较小的情况,可能要进行很多次减法才能达到一次除法的效果,从而使得算法的时间复杂度退化为 \(O(n)\),因此几乎不会用到此算法。


乘法逆元

  • 众所周知,取模有可加、减、乘性:

\[(a+b)\bmod M=(a\bmod M+b\bmod M)\bmod M \]

\[(a-b)\bmod M=(a\bmod M-b\bmod M)\bmod M \]

\[(a\times b)\bmod M=(a\bmod M\times b\bmod M)\bmod M \]

但是,取模是没有可除性的。模意义下的除法如何运算呢?这里引进乘法逆元

  • 定义:若\(a\times x\equiv 1\pmod p\),则称 \(x\) 为 \(a\) 在模 \(p\) 意义下的乘法逆元,记为 \(a^{-1}\pmod p\)。

求逆元

  • 我们可以从 \(a\times x\equiv 1\pmod p\) 这个式子入手。

不难发现,它与 \(\exists y\in\mathbb{Z},ax+by=1\) 等价。

  • 所以它就变成一个关于 \((a,p)\) 的不定方程,可用上一节讲到的\(\text{exgcd}\)解决。

并且可以由裴蜀定理得到:在 \(a\) 在模 \(p\) 意义下的乘法逆元当且仅当 \(\gcd(a,p)=1\),\(a\bot b\)。

  • 代码实现:
inline int solve(int a,int p){
    	int x,y;
    	exgcd(a,p,x,y);//求不定方程ax+py=1的一组解;
    	return x;//求出的x即为a在模p意义下的乘法逆元;
}
  • 当然还可以用费马小定理,即欧拉定理的一种特殊情况求解,这里我们后面再讲。

中国剩余定理(CRT)

  • 缩写为 \(\text{CRT}\),全称为 \(\text{Chinese remainder theorem}\)

  • 一般地,中国剩余定理可以求解以下这类同余方程组

\[\begin{cases}x\equiv a_1\pmod{m_1}\\x\equiv a_2\pmod{m_2}\\\cdots\\x\equiv a_n\pmod{m_n}\end{cases} \]

  • 其中,\(m_1,m_2,\cdots m_n\) 两两互质,则对于任意地整数 \(a_1,a_2,\cdots a_n\) 上面这个方程组有解。

算法流程

  • 举个例子:\(n=3,a=\{2,3,2\},m=\{3,5,7\}\)。

则方程组为:

\[\begin{cases}x\equiv 2\pmod{3}\\x\equiv 3\pmod{5}\\x\equiv 2\pmod{7}\end{cases} \]

  1. 设 \(M=m_1\times m_2\times \cdots \times m=\prod\limits_{i=1}^na_i\)。

\[\therefore M=m_1\times m_2\times m_3=3\times 5\times 7=105 \]

  1. 设 \(M_i=\dfrac{M}{m_i}\)。

\[\therefore\begin{cases}M_1=\dfrac{M}{m_1}=\dfrac{105}{3}=35\\\\M_2=\dfrac{M}{m_2}=\dfrac{105}{5}=21\\\\M_1=\dfrac{M}{m_3}=\dfrac{105}{7}=15\end{cases} \]

  1. 设 \(t_i=m_i^{-1}\) 为 \(M_i\) 模 \(m_i\) 的逆元。(因为 $ M_i\bot m_i$,所以逆元必存在)

\[\therefore\begin{cases} 2\times M_1=2\times 35=70\equiv 1\pmod{3(m_1)},t_1=2\\ 1\times M_2=1\times 21=21\equiv 1\pmod{5(m_2)},t_2=1\\ 1\times M_1=1\times 15=15\equiv 1\pmod{7(m_3)},t_3=1 \end{cases}\]

  1. \(x\) 的通解为 \(a_1 t_1 M_1+a_2 t_2 M_2+\cdots+a_n t_n M_n+kM=\sum\limits^n_{i=1}a_i t_i M_i+kM(k\in \mathbb{Z})\)

\[\begin{aligned}x & =a_1 t_1 M_1+a_2 t_2 M_2+a_3 t_3 M_3\\ & =2\times 2 \times 35+3\times 1 \times 21+ 2\times 1\times 15+k\times 105(k\in \mathbb{Z})\\&=233+k\times 105(k\in \mathbb{Z})\\&=23+k\times 105(k\in \mathbb{Z})\end{aligned} \]

  • 故通解为:\(x=23+k\times 105(k\in \mathbb{Z})\)

例题:P1495 【模板】中国剩余定理(CRT)/ 曹冲养猪

  • 读题可知,题目中的 \(a_i,b_i\) 分别对应上述的 \(m_i,a_i\)。直接使用中国剩余定理解决即可。

  • code:

#include<bits/stdc++.h>
using namespace std;

#define LL long long

inline LL read(){
	LL s=0;int f=1;char ch=getchar();
	while(ch<'0' or ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' and ch<='9'){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
	return f*s;
}

inline void write(LL num){
	if(num<0)putchar('-'),num=-num;
	if(num>9)write(num/10);
	putchar(num%10+48);
}

const int N=15;

LL n,x,y,MM,m[N],a[N],t[N],M[N];

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

int main(){
    n=read();
    MM=1,x=0;
    for(int i=1;i<=n;++i){
        m[i]=read(),a[i]=read();
        MM*=m[i];//M=m1*m2*...mn
    }
    for(int i=1;i<=n;++i){
        M[i]=MM/m[i];//Mi=M/mi
        exgcd(M[i],m[i],t[i],y);//ti=Mi^-1(mod mi)
        t[i]=(m[i]+t[i]%m[i])%m[i];//保证0<=ti<mi
        for(int j=1;j<=a[i];++j)//防止爆long long,用多次加法模拟乘法
            x=(x+M[i]*t[i])%MM;
    }
    write(x);
    return 0;
}

扩展中国剩余定理(exCRT)

  • 因为上述的 \(m_1,m_2,\cdots,m_n\) 两两互质,会使最后构造出来的 \(M_i\) 特别的美好,只用把和式 \(\sum\limits_{1}^n M_i t_i\) 输出就行了,因为其 \(\bmod\ m_1\) 余 \(a_1\),\(\bmod\ m_2\) 余 \(a_2\),$\cdots\ \(,\)\bmod\ m_n$ 余 \(a_n\)。但求 \(M_i\) 需要应用到逆元,因此 \(m_1,m_2,\cdots,m_n\) 必须两两互质

  • 那么当它们两两不互质时,又给如何解决呢?

先从最简单的情况看:假设方程组只有一个方程,即:

\[x\equiv a\pmod m \]

  • 这个式子等价于:\(k\times a+m=x(x\in\mathbb{Z})\),这就是这个同于方程的解系。

  • 再到两个方程,此时很明显无法直接求解。我们是否可以构造一个新的方程,使其解系于原方程组的解系等价呢?即:

\[\begin{cases}x\equiv a_1\pmod{m_1}\\x\equiv a_2\pmod{m_2}\end{cases}\Rightarrow x\equiv a_3\pmod{m_3} \]

答案是肯定的。


算法流程

  • 左边那一个方程组等价于:

\[x=k_1 a_1+m_1=k_2 a_2+m_2 \]

移项,即可得到:

\[k_1 a_1-k_2 a_2=m_2-m_1 \]

因为 \(a_1,a_2,m_2-m_1\) 都是已知的,所以这是的典型的不定方程。

  • 因此可以用裴蜀定理判断是否有解,用 \(\text{exgcd}\) 求解系 \((k_1,k_2)\)。

  • 接下来考虑如何求出一组 \((a_1, a_2)\)。

令 \(d=\gcd(a_1,a_2),p_1=\dfrac{a_1}{d},p_2=\dfrac{a_2}{d}\)。

显然 \(p_1\bot p_2\),所以 \(a_1=p_1 d,a_2=p_2 d\)。

  • 因此原式化为:

\[k_1 p_1-k_2 p_2=\dfrac{m_2-m_1}{d} \]

  • 右边那一串东西是整数,因为当且仅当 \(d|(m_2-m_1)\) 才会有解。左边满足了 \(p_1\bot p_2\),因此求出整个解系是很容易的。现在假设我们拿\(\text{exgcd}\)求出了下面这个方程的解:\((\lambda_1, \lambda_2)\)

\[\lambda_1 p_1+\lambda_2 p_2=1 \]

  • 显然,这是个非常标准的 \(\text{exgcd}\),因此可用这个把 \((\lambda_1,\lambda_2)\) 求出来后,就可以将 \((k_1,k_2)\) 整出来:

\[\begin{cases}k_1=\frac{m_2-m_1}{d}\lambda_1\\k_2=-\frac{m_2-m_1}{d}\lambda2\end{cases} \]

\[\therefore x=m_1+k_1 a_1=m_1+\dfrac{m_2-m_1}{d}\lambda_1 a_1 \]

  • 至此,我们成功地构造出了一个特殊解 \(x\),满足\(\begin{cases}x\equiv a_1\pmod{m_1}\\x\equiv a_2\pmod{m_2}\end{cases}\)。

  • 如何求出整个解系呢?


【定理】 若有特解 \(x'\),那么\(\begin{cases}x\equiv a_1\pmod{m_1}\\x\equiv a_2\pmod{m_2}\end{cases}\)的通解为:\(x'+k\times \text{lcm}(m_1,m_2)(k\in\mathbb{Z})\)

  • 从线性代数的角度讲,这个通解的构造方式是十分平凡的。

对 \(\text{lcm}(m_1,m_2)\) 取模的结果,将整个整数集划分成了 \(\text{lcm}(m_1,m_2)\) 个等价类,哪个等价类里面有特解,那整个等价类肯定全都是解。

接下来唯一需要说明的事情就是:为什么任意一个完全剩余系里面,只会有一个解?这个问题等价于:

  • 为什么在 \(0,1,2,\cdots ,\text{lcm}(m_1,m_2)\) 中,只有一个解?

设上述集合里面有 \(0\leq x,y\leq\text{lcm}(m_1,m_2)\) 满足:

\[\begin{cases}x\equiv a_1\pmod{m_1}\\x\equiv a_2\pmod{m_2}\end{cases},\begin{cases}y\equiv a_1\pmod{m_1}\\y\equiv a_2\pmod{m_2}\end{cases} \]

  • 不妨设 \(x\leq y\),那么:

\[\begin{cases}(x-y)\mod{m_1}=0\\(x-y)\mod{m_2}=0 \end{cases}\Rightarrow \text{lcm}(m_1,m_2)\mid(y-x) \]

\[\because x,y<\text{lcm}(m_1,m_2) \]

\[\therefore y-x<\text{lcm}(m_1,m_2) \]

\[\because \text{lcm}(m_1,m_2)\mid(y-x) \]

\[\therefore y-x=0 \]

\[\therefore x=y \]

  • 因此一个完全剩余系中,有且仅有一个解。

以上就是整个 \(\text{exCRT}\) 算法的全部数学基础。


例题:P4777 【模板】扩展中国剩余定理(exCRT)

  • code:
#include<bits/stdc++.h>
using namespace std;

typedef __int128 ll;

ll x,y,d;
int n;

inline void Exgcd(ll &x,ll &y,ll a,ll b){
    if(b)Exgcd(y,x,b,a%b),y-=a/b*x;
    else d=a,x=1,y=0;
}

inline ll gcd(ll a,ll b){
    ll temp;
    while(b){
        temp=b;
        b=a%b;
        a=temp;
    }
    return a;
}

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

ll a,b,A,B;

inline void merge(){
    Exgcd(x,y,a,A);
    ll c=B-b;
    if(c%d)
        puts("-1"),exit(0);
    x=x*c/d%(A/d);
    if(x<0)
        x+=A/d;
    ll mod=lcm(a,A);
    b=(a*x+b)%mod;
    if(b<0)
        b+=mod;
    a=mod;
}

int main(){
    scanf("%d",&n);
    for(long long i=1,_A,_B;i<=n;++i){
        scanf("%lld %lld",&_A,&_B);
        A=_A,B=_B;
        if(i>1)
            merge();
        else
            a=A,b=B;
    }
    printf("%lld\n",(long long)(b%a));
}

欧拉函数

  • 定义:\(\varphi(n)\) 表示 \(1\sim n\) 中与 \(n\) 互质的数的个数。

它是一个积性函数,即当 \(m\bot n\) 时,\(\varphi(mn)=\varphi(m)\times\varphi(n)\)。

  • 知道了欧拉函数时积性函数后,只需要考虑 \(\varphi(p^k)\) 的取值就能计算所有数的欧拉函数了,其中 \(p\) 为质数。

不难发现若一个数不和 \(p^k\) 互质,则这个数一定是 \(p\) 的倍数,那么 \(1\sim p^k\) 中有 \(\frac{p^k}{p}=p^{k-1}\) 个数和 \(p^k\) 不互质的。反过来和 \(p^k\) 互质的个数就是 \(\varphi(p^k)=p^k-p^{k-1}=p^k(1-\frac{1}{p})\)。

  • 所以设 \(n=p_1^{k_1}p_2^{k_2}\cdots p_m^{k_m}\),则:

\[\varphi(n)=n\left(1-\dfrac{1}{p_1}\right)\left(1-\dfrac{1}{p_2}\right)\cdots\left(1-\dfrac{1}{p_m}\right) \]

  • 可以 \(O(\sqrt{n})\) 计算 \(\varphi(n)\)
inline void solve(){
    	int phi=n;
    	for(int i=2;i*i<=n;++i)
        	if(n%i==0){          //如果i是n的一个质因子
            	phi=phi/i*(i-1); //乘上(1-1/p)
            	while(n%i==0)    //把n中的i全部除掉
                	n/=i;
        	}
    	if(n!=1)
        	phi=phi/n*(n-1);     //n有一个大于sqrt(n)的质因子的情况
}
  • 也可以用线性筛求欧拉函数:
inline void solve(){
    	phi[1]=1;
    	for(int i=2;i<=n;++i){
        	if(!phi[i])                            //phi(i)=0,说明i好没被筛去,是质数
            	p[++tot]=i,phi[i]=i-1;             //phi(p)=p-1
        	for(int j=1;j<=tot and i*p[j]<=n;++j){
            	if(i%p[j]==0)[
                	phi[i*p[j]]=phi[i]*p[j];       //phi(p^k*x)=phi(p^(k-1)*x)*p
                	break;
            	}else
                	phi[i*p[j]]=phi[i]*(p[j]-1);   //phi(p*x)=phi(x)*(p-1)
        	}
    	}
}

欧拉定理

  • 设 \(a,n\in\mathbb{N^+}\),若 \(a\bot n\),则 \(a^{\varphi(n)}\equiv 1\pmod n\)。

当 \(n\) 是一个质数的时候,\(\varphi(n)=n-1\)。因此可以得到费马小定理:

  • 若 \(p\) 为质数,且 \(p\nmid a\),则\(a^{p-1}\equiv 1 \pmod p\)。

因此也可以用费马小定理求逆元:

  • 若 \(p\) 是质数,就可以知道如果 \(a\) 不是 \(p\) 的倍数,就有 \(a\times a^{p-2}=a^{p-1}\equiv 1\pmod p\),根据乘法逆元的定义,\(a\) 在模 \(p\) 意义下的逆元就是 \(a^{p-2}\)。否则逆元不存在。
inline int qPow(int a,int b,int p){//快速幂
	int ans=1;
	while(b>0){
		if(b&1)ans=ans*a%p;
		a=a*a%p;
		b>>=1;
	}
	return ans;
}

inline int solve(int a,int p){
    return qPow(a,p-2,p);
}

  • 对于欧拉定理的证明,这里我会同步举例:
  1. 考虑 \(1\sim n\) 中与 \(n\) 互质的数组成的集合 \(X_n=\{x_1,x_2\cdots x_{\varphi(n)}\}\)

\[\text{取}\ n=12,\text{令}\ a=5 \]

\[\because 5\bot12 \]

\[\therefore\varphi(12)=4 \]

\[\therefore5^{\varphi(12)}\equiv1\pmod{12} \]

\[\therefore a\in X_{12} \]

\[\texttt{同理可得}\ n=12,X_{12}=\{1,5,7,11\} \]

  1. 将 \(X_n\) 集合中的每一个数乘上 \(a\) 再\(\mod {n}\),得到\(X_n'=\{ax_1\bmod{n},ax_2\bmod{n},\cdots\,ax_{\varphi(n)}\bmod{n}\}\)。

\[a=5,X_{12}'=\{5\bmod{12},25\bmod{12},35\bmod{12},55\bmod{12}\}=\{5,1,11,7\} \]

  1. 因为两个集合中的元素都是 \(1\sim n\) 中与 \(n\) 互质的数,并且原来不相同的两个数乘 \(a\) 后依然不可能相同,否则再乘上 \(a\) 后逆元就一样了。所以 \(X_n=X_n'\)。因此可以得出:

\[\left(\prod\limits_{x_i\in X_n}x_i\right)\bmod n=\left(\prod\limits_{x_i\in X_n'}x_i\right)\bmod n=\left(\prod\limits_{x_i\in X_n}ax_i\right)\bmod n=a^{\varphi(n)}\left(\prod\limits_{x_i\in X_n}x_i\right)\bmod n \]

\[\therefore \left(\prod\limits_{x_i\in X_n}x_i\right)\bmod n=a^{\varphi(n)}\left(\prod\limits_{x_i\in X_n}x_i\right)\bmod n \]

两边同乘\(\left(\prod_{x_i\in X_n}x_i\right)\)的逆元,于是有:

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


扩展欧拉定理

  • 设 \(a,n\in\mathbb{N^+}\),若 \(a\bot n\),则 \(a^{2\varphi(n)}\equiv a^{\varphi(n)}\pmod n\)。

比如说,\(2\) 和 \(12\) 不互质,但:

\[2^{2\varphi(12)}=2^8=256\equiv4\pmod {12} \]

\[2^{\varphi(12)}=2^4=16\equiv4\pmod {12} \]

\[\therefore 2^{2\varphi(12)}\equiv2^{\varphi(12)}\pmod{12} \]

  • 两者依旧相同。

考虑扩展欧拉定理的证明。由唯一分解定理,设 \(n=\prod_{i=1}^m p_i^{k_i}\)。

若对于每个 \(i\),我们都可以证明 \(a^{2\varphi(n)}\equiv a^{\varphi(n)}\pmod {p_i^{k_i}}\),则 \(a^{2\varphi(n)}\) 和 \(a^{\varphi(n)}\) 都是下面这个同余方程的解:

\[\begin{cases}x\equiv a^{\varphi(n)}\pmod{ M_1^{k_1}}\\x\equiv a^{\varphi(n)}\pmod{ M_2^{k_2}}\\\cdots\\x\equiv a^{\varphi(n)}\pmod{ M_m^{k_m}}\end{cases} \]

由中国剩余定理的唯一性,扩展欧拉定理也就成立了。下面来分情况讨论:

  • 求证:\(a^{2\varphi(n)}\equiv a^{\varphi(n)}\pmod {p_i^{k_i}}\)
  1. 若 \(a\) 与 \(p_i^{k_i}\) 互质。

设 \(s=\dfrac{n}{p_i^{k_i}}\),那么 \(s\) 和 \(p_i^{k_i}\) 显然也是互质的。由于 \(\varphi(x)\) 是积性函数,所以 \(\varphi(n)=\varphi(s)\varphi(p_i^{k_i})\)。

  • 由欧拉定理:

\[a^{\varphi(n)}=a^{\varphi(s)\varphi(p_i^{k_i})}=a^{\left(\varphi(p_i^{k_i})\right)^{\varphi(s)}}\equiv1^{\varphi(s)}\equiv1\pmod {p_i^{k_i}} \]

两边同乘 \(a^{\varphi(n)}\),即得到 \(a^{2\varphi(n)}\equiv a^{\varphi(n)}\pmod {p_i^{k_i}}\)。

  1. 若 \(a\) 与 \(p_i^{k_i}\) 不互质。

那么 \(a\) 一定是 \(p_i\) 的倍数,\(a^{\varphi(n)}\) 一定是 \(p_i^{\varphi(n)}\) 的倍数。同样设 \(s=\dfrac{n}{p_i^{k_i}}\)。

  • 首先可以用数学归纳法证明 \(p_i^{k_i-1}\geq k_i\)。

当 \(k_i=1\) 时,\(p_i^{k_i-1}=p_i^0=1=k_i\).

当 \(k_i>1\) 时,\(p_i^{k_i-1}=p_i\times p_i^{k_i-2}\geq 2(k_i-1)\geq k_i\)。\(\left(p_i\geq 2,p_i^{k_i-2}\geq k_i-1\right)\)

  • 于是有:

\[\varphi(n)=\varphi(s)\varphi(p_i^{k_i})\geq\varphi(p_i^{k_i})=p_i^{k_i-1}(p_i-1)\geq p_i^{k_i-1}\geq k_i \]

所以 \(p_i^{\varphi(n)}\) 是 \(p_i^{k_i}\) 的倍数,那么 \(a^{\varphi(n)}\) 也就是 \(p_i^{k_i}\) 的倍数。

  • 因此得到:

\[a^{2\varphi(n)}\equiv a^{\varphi(n)}\equiv0\pmod {p_i^{k_i}} \]

综上所述,\(\forall i\in \mathbb{Z}\cap\left[1,m\right] ,a^{2\varphi(n)}\equiv a^{\varphi(n)}\pmod {p_i^{k_i}}\),扩展欧拉定理成立。

  • 将扩展欧拉定理的两边同乘 \(a^{\varphi(n)}\),可以得到 \(a^{3\varphi(n)}\equiv a^{2\varphi(n)}\pmod n\)。

不断重复这个过程,可以得到:

\[a^{\varphi(n)}\equiv a^{2\varphi(n)}\equiv\cdots\equiv a^{k\varphi(n)}\equiv\cdots\pmod n \]

  • 所以对于任意的 \(a,k,n\),就有:\(a^k\equiv a^{(k\text\ {mod}\ \varphi(n))+\varphi(n)}\pmod n\)。

BSGS

拔山盖世Baby Steps Giant Steps

例题:P3846 [TJOI2007] 可爱的质数/【模板】BSGS

  • \(\text{BSGS}\)适用于对于给定的两个互质的正整数 \(a,p\),求一个非负整数 \(x\) 使得:

\[a^x\equiv b\pmod p \]

因为 \(a \bot p\),所以根据欧拉定理:

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

又因为:

\[a^0 \equiv 1\pmod p \]

所以 \(1\sim \varphi(p)\) 是一个循环节。

  • 那么最多循环 \(\varphi(p)\) 次我们能找到答案,否则无解。暴力带么就很容易写出来了。

设 \(x=im-k\),其中 \(0\leq k\leq m\)。

  • 那么方程变为:

\[a^{im-k}\equiv b\pmod p \]

两边同乘 \(a^k\):

\[a^{im}\equiv a^kb\pmod p \]

  • 先计算右边 \(a^kb\mod p\) 的值,把它放到 \(\text{hash}\) 或者 \(\text{map}\) 里。再计算左边 \(a^{im}\mod p\) 的值,从小到大枚举所有可能的 \(i\) 值,再在 \(\text{hash}\) 或者 \(\text{map}\) 里查询。

这里的话倾向用 \(\text{hash}\),因为 \(\text{map}\) 会多带一个 \(\log\)。

时间复杂度:\(O(\max\left(m,\dfrac{\varphi(p)}{m}\right))=O(\sqrt{p})\)

  • code:
#define ll long long
inline ll qPow(ll a,ll b,ll p){
    int ans=1;
    while(b>0){
        if(b&1)ans=ans*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ans;
}
namespace work{
	m=ceil(sqrt(p));
	for(ll i=0,t=n;i<=m;i++,t=t*b%p)
        vis[t]=i;
	for(ll i=1,tt=qPow(b,m,p),t=tt;i<=m;i++,t=t*tt%p)
	    if(vis.count(t))
            write(i*m-vis[t]),exit(0);
	puts("no solution");
}

exBSGS

ex北上广深这玩意还有拓展,用于处理 \(\gcd(a,p)\neq 1\)的情况。

例题:P4195 【模板】扩展 BSGS/exBSGS

  • 首先,上面那个式子可以等价写成:

\[a^x+kp=n \]

  • 设 \(\gcd(a,p)=d\)。由于裴蜀定理,这个式子有解的充要条件是:\(d\mid n\)。

那么上面的式子就是:

\[a^{x-1}\cdot\dfrac{a}{d}+k\cdot\dfrac{p}{d}=\dfrac{n}{d} \]

此时 \(a^x\leftarrow a^{x-1},p\leftarrow\dfrac{p}{d},n\leftarrow\dfrac{n}{d}\)。那么一直递归,直到 \(a\bot p\)。

  • 所以此时设一共递归了 \(\text{cnt}\) 次,这所有次递归的 \(d\) 的乘积是 \(D\)。原式就是:

\[a^{x-cnt}\cdot\dfrac{a^{cnt}}{D}\equiv\dfrac{n}{D}\pmod {\dfrac{p}{D}} \]

那么我们就用 \(a'=a,n'=\dfrac{n}{D},p'=\dfrac{p}{D}\) 来跑一次 \(\text{BSGS}\) 就行了。

  • 最后要再加上 \(\text{cnt}\),并乘上 \(\dfrac{a^{cnt}}{D}\)的系数作为答案。

  • code:

inline int exBSGS(int a,int b,int p){
	a%=p,b%=p;
	if(b==1 or p==1)
        return 0;
	int d,ax=1,cnt=0,x,y;
	while((d=exgcd(a,p,x,y))^1){
		if(b%d)
            return -1;
		b/=d,p/=d,cnt++;
		ax=1ll*ax*(a/d)%p;
		if(ax==b)
            return cnt;
	}
	exgcd(ax,p,x,y);
	int inv=(x%p+p)%p;
	b=1ll*b*inv%p;
	_hash.clear();
	int t=ceil(sqrt(p)),val=1;
	for(int i=0;i<t;i++){
		_hash[1ll*b*val%p]=i;
		val=1ll*val*a%p;
	}
	a=val,val=1;
	if(!a)
        return !b?1+cnt:-1;
	for(int i=0,j;i<=t;i++){
		j=_hash.find(val)==_hash.end()?-1:_hash[val];
		if(~j and i*t-j>=0)
            return i*t-j+cnt;
		val=1ll*val*a%p;
	}
	return -1;
}

Wilson

对于素数 \(p\) 有 \((p-1)!\equiv -1\pmod p\)。

  • 证明:

当 \(p=2\) 时,命题显然成立。

以下设 \(p\geq 3\),此时我们要证 \(\mathbf{Z}_p\) 中所有非零元素的积为 \(\overline{-1}\)。

我们知道 \(\mathbf{Z}_p\) 中所有非零元素 \(a\) 都有逆元 \(a^{-1}\),于是 \(\mathbf{Z}_p\) 中彼此互逆的元素乘积为
\(\overline{1}\)。

但是要注意 \(a\) 和 \(a^{-1}\) 可能相等。若 \(a=a^{-1}\),则 \(a^2\equiv 1\pmod p\),

即 \(0\equiv a^2-1\equiv (a+1)(a-1)\pmod p\),
从而 \(a\equiv 1\pmod p\) 或 \(a\equiv -1\pmod p\)。

这说明:\(\mathbf{Z}_p\setminus\{\overline{0},\overline{1},\overline{-1}\}\) 中所有元素的乘积为 \(\overline{1}\), 进而 \(\mathbf{Z}_p\) 中所有非零元素的积为 \(\overline{-1}\)。

对于整数 \(n\),令 \((n!)_p\) 表示所有小于等于 \(n\) 但不能被 \(p\) 整除的正整数的乘积,即 \((n!)_p=n!/(\lfloor n/p\rfloor !p^{\lfloor n/p\rfloor})\)。

  • Wilson 定理指出 \((p!)_p=(p-1)!\equiv -1\pmod p\) 且可被推广至模素数 \(p\) 的幂次。

应用

阶乘与素数

在某些情况下,有必要考虑以某个素数 \(p\) 为模的公式,包含分子和分母中的阶乘,就像在二项式系数公式中遇到的那样。

只有当阶乘同时出现在分数的分子和分母中时,这个问题才有意义。否则,后续项 \(p!\) 将减少为零。但在分数中,因子 \(p\) 可以抵消,结果将是非零。

因此,要计算 \(n! \bmod p\),而不考虑阶乘中出现因数 \(p\)。写下素因子分解,去掉所有因子 \(p\),并计算乘积模。

用 \((n!)_p\) 表示这个修改的因子。例如:

\[(7!)_p \equiv 1 \cdot 2 \cdot \underbrace{1}_{3} \cdot 4 \cdot 5 \underbrace{2}_{6} \cdot 7 \equiv 2 \bmod 3 \]

  • 这种修正的阶乘,可用于快速计算各种带取模和组合数的公式的值。

计算余数的算法

计算上述去掉因子 \(p\) 的阶乘模 \(p\) 的余数。

\[\begin{aligned}(n!)_p &= 1 \cdot 2 \cdot 3 \cdot \ldots \cdot (p-2) \cdot (p-1) \cdot \underbrace{1}_{p} \cdot (p+1) \cdot (p+2) \cdot \ldots \cdot (2p-1) \cdot \underbrace{2}_{2p} \\\\&\quad \cdot (2p+1) \cdot \ldots \cdot (p^2-1) \cdot \underbrace{1}_{p^2} \cdot (p^2 +1) \cdot \ldots \cdot n \pmod{p} \\\\&= 1 \cdot 2 \cdot 3 \cdot \ldots \cdot (p-2) \cdot (p-1) \cdot \underbrace{1}_{p} \cdot 1 \cdot 2 \cdot \ldots \cdot (p-1) \cdot \underbrace{2}_{2p} \\\\&\cdot 1 \cdot 2 \quad \cdot \ldots \cdot (p-1) \cdot \underbrace{1}_{p^2} \cdot 1 \cdot 2 \cdot \ldots \cdot (n \bmod p) \pmod{p} \end{aligned}\]

  • 可以清楚地看到,除了最后一个块外,阶乘被划分为几个长度相同的块。

\[\begin{aligned} (n!)_p&= \underbrace{1 \cdot 2 \cdot 3 \cdot \ldots \cdot (p-2) \cdot (p-1) \cdot 1}_{1\text{st}} \cdot \underbrace{1 \cdot 2 \cdot 3 \cdot \ldots \cdot (p-2) \cdot (p-1) \cdot 2}_{2\text{nd}} \cdot \ldots \\\\& \cdot \underbrace{1 \cdot 2 \cdot 3 \cdot \ldots \cdot (p-2) \cdot (p-1) \cdot 1}_{p\text{th}} \cdot \ldots \cdot \quad \underbrace{1 \cdot 2 \cdot \cdot \ldots \cdot (n \bmod p)}_{\text{tail}} \pmod{p} \end{aligned}\]

  • 块的主要部分 \((p-1)!\ \mathrm{mod}\ p\) 很容易计算,可以应用 Wilson 定理:

\[(p-1)!\equiv -1\pmod p \]

总共有 \(\lfloor \frac{n}{p} \rfloor\) 个块,因此需要将 \(\lfloor \frac{n}{p} \rfloor\) 写到 \(1\) 的指数上。可以注意到结果在 \(-1\) 和 \(1\) 之间切换,因此只需要查看指数的奇偶性,如果是奇数,则乘以 \(-1\)。除了使用乘法,也可以从结果中减去 \(p\)。

最后一个部分块的值可以在 \(O(p)\) 的时间复杂度单独计算。

这只留下每个块的最后一个元素。如果隐藏已处理的元素,可以看到以下模式:

\[(n!)_p = \underbrace{ \ldots \cdot 1 } \cdot \underbrace{ \ldots \cdot 2} \cdot \ldots \cdot \underbrace{ \ldots \cdot (p-1)} \cdot \underbrace{ \ldots \cdot 1 } \cdot \underbrace{ \ldots \cdot 1} \cdot \underbrace{ \ldots \cdot 2} \cdots \]

这也是一个修正的阶乘,只是维数小得多。它是:

\[\left(\left\lfloor \frac{n}{p} \right\rfloor !\right)_p \]

因此,在计算修改的阶乘 \((n!)_p\) 中,执行了 \(O(p)\) 个操作,剩下的是计算 \((\lfloor \frac{n}{p} \rfloor !)_p\),于是有了递归,递归深度为 \(O(\log_p n)\),因此算法的总时间复杂度为 \(O(p \log_p n)\)。

  • 可以预先计算阶乘 \(0!, 1!, 2!, \dots, (p-1)!\pmod p\),那么时间复杂度为 \(O(\log_p n)\)。

计算余数算法的实现

具体实现不需要递归,因为这是尾部递归的情况,因此可以使用迭代轻松实现。在下面的实现中预计算了阶乘 \(0!, 1!, \dots, (p-1)!\)。

因此时间复杂度为 \(O(p + \log_p n)\)。如果需要多次调用函数,则可以在函数外部进行预计算,于是计算 \((n!)_p\) 的时间复杂度为 \(O(\log_p n)\)。

  • code
inline int factmod(int n, int p){
    vector<int>f(p);
    f[0]=1;
    for(int i=1;i<p;i++)
        f[i]=f[i-1]*i%p;
    int res=1;
    while(n>1){
        if((n/p)%2)
            res=p-res;
        res=res*f[n%p]%p;
        n/=p;
    }
    return res;
}

如果空间有限,无法存储所有阶乘,也可以只存储需要的阶乘,对它们进行排序,然后计算阶乘 \(0!,~ 1!,~ 2!,~ \dots,~ (p-1)!\) 而不显式存储它们。


Lucas

Lucas 定理内容如下:对于质数 \(p\),有:

\[\dbinom{n}{m}\bmod p=\dbinom{\left\lfloor n/p\right\rfloor}{\left\lfloor m/p\right\rfloor}\cdot\dbinom{\left\lfloor n\bmod p\right\rfloor}{\left\lfloor m\bmod p\right\rfloor}\bmod p \]

观察上述表达式,可知 \(n\bmod p\) 和 \(m\bmod p\) 一定是小于 \(p\) 的数,可以直接求解。\(\dbinom{\left\lfloor n/p\right\rfloor}{\left\lfloor m/p\right\rfloor}\) 可以继续用 Lucas 定理求解。这也就要求 \(p\) 的范围不能够太大,一般在 \(10^5\) 的级别。

边界条件:当 \(m=0\) 的时候,返回 \(1\)。

时间复杂度为 \(O(f(p) + g(n)\log n)\),其中 \(f(n)\) 为预处理组合数的复杂度,\(g(n)\) 为单次求组合数的复杂度。


Lucas证明

  • 考虑
    \(\displaystyle\binom{p}{n}\bmod p\)的取值,注意到 \(\displaystyle\binom{p}{n}=\frac{p!}{n!(p-n)!}\),分子的质因子分解中 \(p\) 的次数恰好为 \(1\)。

因此只有当 \(n = 0\) 或 \(n = p\) 的时候 \(n!(p-n)!\) 的质因子分解中含有 \(p\),即 \(\displaystyle\binom{p}{n} \bmod p = [n = 0 \vee n = p]\)。进而我们可以得出:

\[\begin{aligned} (a+b)^p &= \sum_{n=0}^p \binom pn a^n b^{p-n}\\ &\equiv \sum_{n=0}^p [n=0\vee n=p] a^n b^{p-n}\\ &\equiv a^p + b^p \pmod p \end{aligned}\]

注意过程中没有用到费马小定理,因此这一推导不仅适用于整数,亦适用于多项式。因此我们可以考虑二项式 \(f^p(x)=(ax^n + bx^m)^p \bmod p\) 的结果:

\[\begin{aligned} (ax^n + bx^m)^p &\equiv a^p x^{pn} + b^p x^{pm} \\ &\equiv ax^{pn} + bx^{pm}\\ &\equiv f(x^p) \end{aligned}\]

考虑二项式 \((1+x)^n \bmod p\),那么
\(\displaystyle\binom n m\) 就是求其在 \(x^m\) 次项的取值。使用上述引理,我们可以得到:

\[\begin{aligned} (1+x)^n &\equiv (1+x)^{p\lfloor n/p \rfloor} (1+x)^{n\bmod p}\\ &\equiv (1+x^p)^{\lfloor n/p \rfloor} (1+x)^{n\bmod p} \end{aligned}\]

注意前者只有在 \(p\) 的倍数位置才有取值,而后者最高次项为 \(n\bmod p \le p-1\),因此这两部分的卷积在任何一个位置只有最多一种方式贡献取值,即在前者部分取 \(p\) 的倍数次项,后者部分取剩余项,即:

\[\dbinom{n}{m}\bmod p=\dbinom{\left\lfloor n/p\right\rfloor}{\left\lfloor m/p\right\rfloor}\cdot\dbinom{\left\lfloor n\bmod p\right\rfloor}{\left\lfloor m\bmod p\right\rfloor}\bmod p \]

Code

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

inline LL read(){
	LL s=0,f=1;char ch=getchar();
	while(ch<'0' or ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' and ch<='9'){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
	return f*s;
}

inline void write(LL num){
	if(num<0)putchar('-'),num=-num;
	if(num>9)write(num/10);
	putchar(num%10+48);
}

const int N=1e5+5;
LL fac[N];
int T,a,b,m;

inline LL Pow(LL a,LL n,LL ma){
	LL ans=1;a%=m;
	while(n){
		if(n&1)ans=(ans*a)%m;
		a=(a*a)%m;
		n>>=1;
	}
	return ans;
}

inline LL inverse(LL a,LL m){
	return Pow(fac[a],m-2,m);
}

inline LL C(LL n,LL r,LL m){
	if(r>n)return 0;
	return (fac[n]*inverse(r,m))%m*inverse(n-r,m)%m;
}

inline LL lucas(LL n,LL r,LL m){
	if(r==0)return 1;
	return C(n%m,r%m,m)*C(n/m,r/m,m)%m;
}

int main(){
	T=read();
	while(T--){
		a=read(),b=read(),m=read();
		fac[0]=1;
		for(int i=1;i<=m;i++)
			fac[i]=(fac[i-1]*i)%m;
		write(lucas(a+b,a,m));
		puts("");
	}
	return 0;
}

标签:入门,数论,bmod,varphi,cdot,int,pmod,进门,equiv
From: https://www.cnblogs.com/QcpyWcpyQ/p/18017039

相关文章

  • 多项式从入门到进门
    多项式全家福多项式一个以\(x\)为变量的多项式定义在一个代数域\(F\)上,将函数\(A(x)\)表示为形式和:\[A(x)=\sum\limits_{i=0}^{n-1}a_ix^i\]我们称\(a_0,a_1,\cdots,a_n\)为多项式的系数,所有系数都属于数域\(\mathbbF\)。如果一个多项式的最高次的非零系数是\(k......
  • 生成函数从入门到进门
    引入先看下面这个例子:\[(1+a_1x)\times(1+a_2x)\times\cdots\times(1+a_nx)\]拆括号得:\[1+(a_1+a_2+\cdots+a_n)x+(a_1a_2+a_1a_3+\cdots+a_{n-1}a_n)x^2+\cdots+(a_1a_2\cdotsa_n)x^n\]其中\(x^2\)的系数包含了从\(n\)个元素\(\{a_1,a_2,\cdots,a_n\}\)中选取两个的......
  • 概率期望从入门到进门
    概率的线性性定义:\(\mathbb{E}(X)=\sum_i\timesP(X=i)\)。其中\(x\)为变量。线性性\[\begin{aligned}\mathbb{E}(aX+bY)&=\sumi\timesP(aX+bY=i)\\&=\sumi\sum_j\sum_k[j+k=i]P(aX=j)P(bY=k)\\&=\sum_j\sum_k(j+k)P(aX=j)\cdotP(bY=k)\\&......
  • HydroOJ 从入门到入土(13)批量修改题号前缀
    题库的管理,无论是用前缀来分组,还是用域来分组,都有不好管理的地方,尤其是题号。有的时候导入了一堆题,导入完发现题号不是自己想要的,但删起来很麻烦,一个一个改更不现实,真是欲哭无泪。本文主要记录了一次批量修改题号前缀的过程,仅供参考。修改中涉及数据库操作,修改前一定要现在虚......
  • 数论基础
    数论:研究数与数之间的关系。如带余除法、因数倍数、同余整除等都是数论。【筛法】主要使用的筛法有两个:埃氏筛和欧拉筛(线性筛)。使用筛法的原因很简单:对于一个数,我们要找它的因数不容易;但是对于一个因数,我们找它的倍数很简单。【埃氏筛】因为一个数的倍数一定不是质数,且任何数......
  • 拓扑排序入门
    目录写在前面一些概念算法步骤字典序最大/最小的拓扑序列?模板例题3704.排队家谱树奖金P1983[NOIP2013普及组]车站分级1639.拓扑顺序写在前面昨晚cfdiv3的F就是一道基本上可以说板子的拓扑排序的题目,没有做出来感觉图论很早之前就看了,但是基本没有刷过什么题,开始补一下图论......
  • 掌握C语言文件操作:从入门到精通的完整指南!
    ✨✨欢迎大家来到贝蒂大讲堂✨✨......
  • pytorch深度学习入门(8)之-Torchaudio使用Tacotron2 文本转语音
    https://blog.csdn.net/ajunbin859/article/details/134380417?ops_request_misc=&request_id=&biz_id=102&utm_term=pytorch%E7%89%88%E6%9C%AC%E7%9A%84tacotron%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B&utm_medium=distribute.pc_search_r......
  • day04_操作系统入门
    今日笔记学操作系统基础概念linux系统linux系统(centos)+vmware安装起来(网络配置,磁盘分区)ubuntu安装xshell服务器的远程连接服务器网站的前后端,数据库app的前后端,数据库微信、腾讯微信的服务器移动端设备上,安装的微信客户端在线笔记笔记对运维来说,就是一个宝藏,mar......
  • day21_乌班图入门
    .请解释yum缓存,如何理解、如何管理去网络源下载软件rpm包,会涉及网络延时,网络资源消耗1.解决,关于yum缓存包的理解(自己搭建yum仓库)11.当你拿到一个初始化的机器,默认安装的软件(centos上的rpm格式的软件)数量可能很少导致你后期使用各种工具,会报错,比如python调用gzip解压缩功能s......