初等数论——同余

这篇具有很好参考价值的文章主要介绍了初等数论——同余。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前置

模运算

定义: \(a \% b (a\mod b)\) ,表示 \(a\) 除以 \(b\) 的余数。

加法: \((a+b) \% p\)
减法: \((a-b+p) \% p\) 。加 \(p\) 是为了防止负数。
乘法: \((a \times b) \% p\)
除法无法直接运算,要用逆元(在下面会讲到)。
平方运算: 快速幂

模运算满足: 结合律,交换律,分配律

同余的定义及其性质

定义:\(a,b\) 除以 \(m\) 的余数相同,则称 \(a,b\)\(m\) 同余,记作 \(a \equiv b(\mod m)\)

由对于模n同余的所有整数组成的这个集合称为同余类(congruence class或residue class) 。

\(m\) 的同余类一共有 \(m\) 个,它们构成 \(m\)完全剩余系

\(1\)\(m\) 中与 \(m\) 互质的数代表的同余类共有 \(\varphi(m)\) 个,它们构成了 \(m\) 的简化剩余系。

性质1: 满足对称性,同加性,同乘性,同幂性。

性质2:\(a \equiv b(\mod p),c \mid a,c \mid b\),则 \(a \equiv b(\mod \dfrac{m}{\gcd(m,c)})\)

费马小定理

\(p\) 是质数,\(\forall a \in Z,a^{p} \equiv a (\mod p)\) 。当 \(a,p\) 互质时,则有 \(a^{p-1} \equiv 1(\mod p)\)

引理:当 \(p\) 是质数时,其因子只有 \(1\)\(p\) 两个。因此,若两个数相乘是 \(p\) 的倍数,其中必然至少有一个是 \(p\) 的倍数。
\(a\) 不是 \(p\) 的倍数时,不存在 \(x \neq y\)\(1 \leq x,y < p\) 使得 \(a \times y \equiv a \times x(\mod p)\)\(x-y<p\)\(p\) 的倍数,与 \(1 \leq x,y < p\) 的限制矛盾。
进一步地,考虑 \(1 \sim p-1\) 所有数,它们乘以 \(a\) 之后在模 \(p\) 意义下互不相同,说明仍得 \(1 \sim p-1\) 所有数。
因此,\(\prod_{i=1}^{p-1}i \equiv \prod_{i=1}^{p-1}ai(\mod p)\)。又因为 \(\prod_{i=1}^{p-1}i\)显然不是 \(p\) 的倍数,所以费马小定理成立。

欧拉定理

若正整数 \(a,n\) 互质,\(a^{\varphi(n)} \equiv 1(\mod n)\) 其中 \(\varphi(n)\) 为欧拉函数。

\(x_1,x_2 \cdots x_{\varphi(n)}\) 是模 \(n\) 的简化剩余系,那 \(ax_1,ax_2, \cdots ax_{\varphi(n)}\) 也是模 \(n\) 的简化剩余系。
因为 \(\gcd(a,n)=1\)\(ax_1 \dot a x_2 \cdots ax_{\varphi(n)} \equiv x_1,x_2 \cdots x_{\varphi(n)} (\mod n)\) ,所以欧拉定理成立。

可以发现费马小定理是欧拉定理的一种特殊情况。

扩展欧拉定理

\(a,n\) 互质,\(a^b \equiv a^{b \mod \varphi(n)}\)

\(a,n\) 不互质,当 \(b>\varphi(n)\) 时,\(a^{b \equiv \varphi(n)+\varphi(n)}\)

因为证明有些复杂,见oi wiki 。

扩展欧拉定理可以用来降幂,当幂太大时,此公式可以减小复杂度,而当 \(b< \varphi(n)\) 幂比较小,就没有必要降幂了。

例题:P4139 上帝与集合的正确用法

线性同余方程

裴蜀定理

定义: \(a,b\) 是不全为零的整数,对于任意整数 \(x,y\) , $\gcd(a,b) \mid ax + by $ ,且存在整数 \(x,y\),使得 $ax +by = \gcd(a,b) $。

逆定理:\(a,b\) 是不全为零的整数,若 \(d>0\)\(a,b\) 的公约数,且存在整数 \(x,y\),使得 $ ax +by = d$,则 \(d = \gcd(a,b)\)

特殊地,设 \(a,b\) 是不全为零的整数,若存在正整数 \(x,y\) ,使得 $ax +by =1 $ ,则 \(a,b\) 互质。

当有 \(n\) 个数时,此定理依然成立。

例题: P4549 【模板】裴蜀定理

code
#include<bits/stdc++.h>
using namespace std;
int n;
int gcd(int x,int y)
{
	return y==0?x:gcd(y,x%y); 
}
int main()
{
	scanf("%d",&n);
	int x,y;
	cin>>x;
	for(int i=2;i<=n;i++)
	{
		cin>>y;
		x=gcd(x,y);
	}
	cout<<abs(x)<<endl;
	return 0;
 } 

扩展欧几里得算法

上文裴蜀定理,讲述了存在整数 \(x,y\),使得 $ax +by = \gcd(a,b) $ ,这里讲述如何求解 \(x,y\)

我们设 \(d=gcd(a,b)\)。可以用辗转相除法法求出两个数的 $ \gcd$ ,所以我们假设它的另一个解是\(x2,y2\),满足

\[b \times x2+(a \bmod b) \times y2=gcd(a,b) \]

也就是

\[b \times x2+(a \bmod b) \times y2=a \times x+b \times y \]

又因

\[a \mod b=a-b \times (a/b) \]

代入拆开得

\[a \times y2+(x2-y2 \times (a/b))=a \times x+b \times y \]

可得一个解

\[x=y2,y=x2-y2*(a/b) \]

现在发现只需要求出 \(x2,y2\) 而我们观看一下求 \(x,y\) 的式子,就是辗转相除法的式子,所以我们只需递推求一下 \(x2,y2,x3,y3\)等。

考虑一下递推边界,当递推到\(b=0\) 时,

\[a \times x+b \times y= \gcd(a,b) \]

可转换成

\[a \times x= \gcd(a,b)=a \]

显然 \(x=1,y \in Z\) 时 ,方程成立。

这样就求出了方程的一组特解,我们设为 \(x_0,y_0\)

显然不定方程 $ax +by = \gcd(a,b) $ 有无穷解,所以要求通解形式。

可以知道 $ \Delta(ax)+\Delta(by)=0$ ,设 \(\Delta =\lvert \Delta (ax) \rvert = \lvert \Delta (by) \rvert\),那 \(a,b \mid \Delta\)\(lcm(a,b) \mid \Delta\) ,所以 $ \Delta x$ 是 \(\dfrac{lcm(a,b)}{a}=\dfrac{b}{d}\) 的倍数,$ \Delta y$ 是 \(\dfrac{lcm(a,b)}{b}=\dfrac{a}{d}\) 的倍数。

所以通解为:

\[\begin{aligned} \begin{cases} x=x_0+\dfrac{b}{d} \times k\\ y=y_0-\dfrac{a}{d} \times k\\ \end{cases} \end{aligned} \]

这里 \(k \in Z\)

实际做题时,会让求 \(x\) 的最小正整数解,设 \(t= \dfrac{b}{d}\)

\[x=(x \mod+t) \mod t \]

特解的数据范围:ycx 的文章 关于 exgcd 求得特解的数值范围

线性同余方程

定义:形如 \(a \times x\equiv c (\mod b) ,a,b \in Z\) 的方程叫做线性同余方程

求法:

原式转换成 :

\[a \times x + b \times y=c,y \in Z \]

这个式子和扩展欧几里得算法可以求的式子有点关联。

\[a \times x+b \times y=gcd(a,b) \]

\(d=\gcd(a,b)\) ,由裴蜀定理可知,方程有解当 \(d \mid c\)

原式又可转成:

\[a \times \frac{\gcd(a,b)}{c} \times x+b \times \frac{\gcd(a,b)}{c} \times y=\gcd(a,b) \]

这样用扩展欧几里得算法就可以求出。

模板: P1082 [NOIP2012 提高组] 同余方程

code
#include<bits/stdc++.h>
#define int long long
using namespace std;
int c,d,x,y;
int exgcd(int a,int b,int &x,int &y)
{
	if(b==0)
	{
		x=1,y=1;
		return a;
	}
	int t=exgcd(b,a%b,y,x);
	y-=(a/b)*x;
	return t;
}
signed main()
{
	scanf("%lld%lld",&c,&d);
	exgcd(c,d,x,y);
	printf("%lld",(x%d+d)%d);
	return 0;
}

线性同余方程组(中国剩余定理)

\[\begin{aligned} \begin{cases} x \equiv a_1 (\mod m_1)\\ x \equiv a_2 (\mod m_2)\\ \cdots \\ x \equiv a_n (\mod m_n)\\ \end{cases} \end{aligned} \]

中国剩余定理(crt)

上式子中 \(a \in Z,m \in N^*,(a,m)=1\)

求解方法:

\(M=m_1 \times m_2 \times \cdots m_n\)

\(b_i=\dfrac{M}{m_i}\)\(b_i^{-1}\)\(b_i\)\(m_i\) 下的逆元。

\(x= \sum_{i=1}^{n} a_i \times b_i \times b_i^{-1}\)

证明:

尝试为每个同余方程设一个 $ x_i,x_i \equiv a_i (\mod m_i)$,可以知道 $ x_i \equiv 0(mod m_j) j \neq i$,记为条件一。

\(x_i\)\(b_i\) 的倍数,如果要满足条件一 \(x_i=b_i\times a_i\) 即可,
那要满足上面新设的同余方程,让 \(x_i \times b_i^{-1}\) 即可,如果要让所以 \(x_i\) 合成一个 \(x\),加起来就可以了。

扩展中国剩余定理(excrt)

上面没看懂?没关系有更好理解并适用更广的扩展中国剩余定理(excrt),它不要求模数互质。

本质就是合并方程,我们把两个方程合并成新一个方程,依次类推就可以求解方程组了。

具体的说:合并方程 \(x \equiv a_1 (mod m_1)\)\(x \equiv a_2 (mod m_2)\)

设 $x = a_1+p \times m_1 $,所以

\[a_1 +p \times m_1 \equiv a_2 (mod m_2) \]

即:

\[p \times m_1 +q \times m_2 \equiv a_2 - a_1 (mod m_2) \]

这个地方可以用 exgcd 求解。

最后合并得到:

\[x \equiv a_1 +p \times m_1(mod (lcm(m_1,m_2))) \]

根据 裴蜀定理\(gcd(m_1,m_2)\) 不是 \(a_2-a_1\) 因数时,方程无解。

模板:

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

code
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
int a[20],b[20],ans,M=1,t[20],m[20];
int x,y;
int exgcd(int a,int b)
{
	if(b==0)
	{
		x=1,y=0;
		return a;
	}
	exgcd(b,a%b);
	int t=y;
	y=x-a/b*y;
	x=t;
}
signed main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>b[i]>>a[i],M*=b[i];
	for(int i=1;i<=n;i++)
	{
		exgcd(M/b[i],b[i]);
		t[i]=x;
		t[i]=(t[i]%b[i]+b[i])%b[i];
	}
	for(int i=1;i<=n;i++)
	{
		ans+=a[i]*(M/b[i])*t[i]%M;
	}
	cout<<ans%M<<endl;
	return 0;
}

P4777 【模板】扩展中国剩余定理(EXCRT)

code
#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int N=1e7+10;
int n;
int m[N],X[N];
int  exgcd(int a, int b,int &x,int &y)
{
	if(b == 0) 
	{ 
		x = 1;
		y = 0;
		return a;
	} 
	int d=exgcd(b, a % b,x,y);
	long long tx = x;
	x = y;
	y = tx - a / b * y; 
	return d;
}
int mul(int a,int b,int mod)
{
	int res=0;
	while(b)
	{
		if(b&1)res=(res+a)%mod;
		a+=a;
		a%=mod;
		b>>=1;
	}
	return res;
}
signed main()
{
	int x,y,ans=0;
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
	cin>>m[i]>>X[i];
	int a1=X[1],m1=m[1];
	for(int i=2;i<=n;i++)
	{
		int a2=X[i],m2=m[i];
		int a=m1,b=m2,c=(a2-a1%m2+m2)%m2;
		int d=exgcd(a,b,x,y);
		if(c%d!=0)
		{
			puts("-1");
			return 0;
		}
		x=mul(x,(c/d),(b/d));
		ans=a1+x*m1;
		m1=m2/d*m1;
		ans=(ans%m1+m1)%m1;
		a1=ans;
	}
	cout<<ans<<endl;
	return 0;
}

乘法逆元

定义

如果一个线性同余方程 \(ax \equiv 1 (\mod b)\)\(x\) 称为 \(a \mod b\) 的逆元,记作 \(a^{-1}\)

应用: 上文提到除法无法直接取模,而用乘法逆元就可以求出。

根据定义可知 \(a \times a^{-1}=1\) ,那

\[a \div b=\dfrac{a \times 1}{b}= \dfrac{a \times b \times b^{-1}}{b}=a \times b^{-1} \]

求解方法

求单个数的乘法逆元

当模数 \(p\) 为质数时,可以用 费马小定理 求解

由定义知,\(x\)\(a\) 的乘法逆元

\[ax \equiv 1 (\mod p) \]

再由费马小定理得:

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

所以

\[x \equiv a^{p-2} (\mod p) \]

用快速幂就可以求出

code
int qpow(long long a, int b) {
  int ans = 1;
  a = (a % p + p) % p;
  for (; b; b >>= 1) {
    if (b & 1) ans = (a * ans) % p;
    a = (a * a) % p;
  }
  return ans;
}
int main()
{
	a=qpow(a,p-2);//求 a 的逆元
}

\(p\) 不为质数, \(\gcd(a,p)=1\) 时,可以用扩展欧几里得算法求出。(\(p\) 不为质数时也可以求)。

求乘法逆元本质上就是求线性同余方程,用求线性同余方程的方法求就可以了。

线性求 \(1 \cdots n\) 的逆元

用递推来求逆元,当递推到 \(i\) 时,设 \(k= \lfloor \dfrac{p}{i} \rfloor ,j= p \mod i\),所以

\[p=k \times i + j \]

由此又可以推出

\[k \times i + j \equiv 0 (\mod p) \]

两边同乘 \(i^{-1} \times j^{-1}\) 得:

\[j^{-1} \times k+i^{-1} \equiv 0(\mod p) \]

所以

\[i^{-1} \equiv -k \times j^{-1} (\mod p) \]

既然是递推式,就要关注递推的起始项,当 \(i=1\) 时,\(1\) 的模任何数的逆元都是 \(1\)

code
inv[1] = 1;
for (int i = 2; i <= n; ++i) {
  inv[i] = (p - p / i) * inv[p % i] % p;
}

代码中 \(p - p/i\) 是为了防负数。

求任意 \(n\) 个数的逆元

要求 \(a_1 \cdots a_n\) 的逆元。

定义两个数组 \(s,sv\)\(s_i\) 表示前 \(i\) 个数的乘积, \(sv_i\) 表示前 \(i\) 个数的逆元的乘积,那这样 \(a_i\) 的逆元就是 \(s_{i-1} \times sv_i\)

递推边界 \(s_0=1\)\(sv_n=s_n\) 的逆元。文章来源地址https://www.toymoban.com/news/detail-850092.html

code
s[0] = 1;
for (int i = 1; i <= n; ++i) s[i] = s[i - 1] * a[i] % p;
sv[n] = qpow(s[n], p - 2);
for (int i = n; i >= 1; --i) sv[i - 1] = sv[i] * a[i] % p;
for (int i = 1; i <= n; ++i) inv[i] = sv[i] * s[i - 1] % p;

原根

到了这里,关于初等数论——同余的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Python】机器学习基础前置:矩阵的表示与定义 | Numpy 库 | Identity 身份矩阵 | 逆矩阵和转置

        💭 写在前面: 我们先介绍线性方程体系的基本概念和矩阵表示方法,矩阵的定义、加法、乘法、逆矩阵、转置和标量乘法等。然后讲解如何解决线性方程组问题,包括解集形式、行阶梯形矩阵、计算逆置和解决线性方程组的算法等。本节将补充线性代数的基础知识,为

    2024年02月02日
    浏览(43)
  • 7-2 数论中的模幂运算

    欧拉函数法可以解决模幂运算 给定伪代码的思想

    2024年02月05日
    浏览(37)
  • 【第二章:数据的表示和运算】

    探讨的两大主题:一步步递进 那么现在就需要探究 数据如何以2进制的形式在计算机中表示的呢?? 那么还有就是计算机如何进行数据的算术和逻辑运算的?? 我们平常使用的是10进制的数据,然而计算机能够识别的是2进制的01序列串。 主要是权重的不同。一方面符号表示

    2024年02月04日
    浏览(46)
  • 计算机组成原理 --- 数据的表示和运算

    一.进位计数制   1.由位置确定的权重为位权 --- 比如个位的位权是10的0次方,十位的位权是10的1次方... 1.十进制的基数是 --- 0,1,2,3,4,5,6,7,8,9 ,二进制的基数是0,1....其它同理  1.规定 --- 在进制中,当数字大于9的时候,就都用大写字母来表示 --- 如A表示10,B表

    2023年04月08日
    浏览(54)
  • apifox前置自定义脚本,生成签名

    为了防止API调用过程中被黑客恶意篡改,调用任何一个API都需要携带签名,TOP服务端会根据请求参数,对签名进行验证,签名不合法的请求将会被拒绝 使用apifox工具每次访问都要填写签名很麻烦,写个脚本自动生成签名,解决这种麻烦事 第四步:开始写脚本,脚本代码如下

    2024年02月11日
    浏览(35)
  • 王道计组(23版)2_数据的表示和运算

    十进制转换为二进制: 原码: [+0] 原 =0,0000 [-0] 原 =1,0000 -1无法表示 补码: 按位取反,末位加1 [+0.0000] 补 =[-0.0000] 补 =0.00000 反码: 按位取反 [+0] 反 =0,0000 [-0] 反 =1,1111 移码: 与补码仅符号位不同 [-X] 补 :[X] 补 连同符号位一起去反,末位加1,(X0) 主存地址通常用 无符号

    2023年04月21日
    浏览(32)
  • 离散数学-集合论-关系的概念、表示和运算(7)

    函数是x 到y 的映射,这种映射反就是一种关系。因为定义域x 是一个集合、值域y 也是一个集合所以函数就是一个x, y 有序对的集合。因此,我们可以通过二元关系来定义函数的概念,利用有序对的集合来表示函数。 1.1 有序对 定义: 由两个元素 x 和 y,按照一定的顺序组成的

    2024年02月06日
    浏览(48)
  • 【数学】【记忆化搜索 】【动态规划】964. 表示数字的最少运算符

    【动态规划】【字符串】【表达式】2019. 解出数学表达式的学生分数 动态规划汇总 数学 记忆化搜索 给定一个正整数 x,我们将会写出一个形如 x (op1) x (op2) x (op3) x … 的表达式,其中每个运算符 op1,op2,… 可以是加、减、乘、除(+,-,*,或是 /)之一。例如,对于 x = 3,

    2024年02月22日
    浏览(52)
  • 用链表表示多项式,并实现多项式的加法运算

    输入格式: 输入在第一行给出第一个多项式POLYA的系数和指数,并以0,0 结束第一个多项式的输入;在第二行出第一个多项式POLYB的系数和指数,并以0,0 结束第一个多项式的输入。 输出格式: 对每一组输入,在一行中输出POLYA+POLYB和多项式的系数和指数。 输入样例: 输出样例: 本

    2024年02月07日
    浏览(71)
  • 码出高效_第一章 | 有意思的二进制表示及运算

    设想有8条电路,每条电路有高电平和低电平两种状态,即就有2 8 =256种不同的信号。假设其表示区间为0~255,最大数即2 8 -1。 那么32条电路能够表示最大数为(2 32 -1)=4294967295,即所谓的32位电路信号。 正负数表示: 上面的8条电路,最左侧一条表示正负:0-整数,1-负数,不

    2024年02月06日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包