数论学习笔记 - 同余及其拓展知识

同余定义

若 a,b 为两个整数,且它们的差 a-b 能被某个自然树 m 所整除,则称 a 就模 m 来说同余于 b,或者说 a 和 b 关于模 m 同余,记为:a\equiv b(modm)。它意味着:a-b=m*k(k为某一个整数)。

同余类与剩余系

对于任意a∈[0,m-1],集合 {a+km}(k属于Z) 的所有数模 m 同余,余数都是 a。该集合称为一个模 m 的同余类,简记为\bar{a}

模 m 的同余类一共有 m 个,分别为 \bar{0},\bar{1},\bar{2},...,\bar{m-1}。它们构成 m 的完全剩余系

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

简化剩余系关于模 m 乘法封闭。这是因为若 a,b(1≤a,b≤m) 与 m 互质,则 a*b 也不可能与 m 含有相同的质因子,即 a*b 也与 m互质。再由余数的定义即可得到 a*b mod m 也与 m 互质,即 a*b mod m 也属于 m 的简化剩余系。

快速幂

根据数学常识,每一个正整数可以唯一表示为若干指数不重复的2的次幂的和。也就是说,如果 b 在二进制表示下有 k 位,其中第 i(0≤i<k) 位的数字是 ci,那么:

b=c_{k-1}2^{k-1}+c_{k-2}2^{k-2}+...+c_{0}2^{0}

于是:

a^{b}=a^{c_{k-1}*2^{k-1}}*a^{c_{k-2}*2^{k-2}}*...*a^{c_{0}*2^{0}}

所以我们很容易通过 k 次递推求出每个乘积项,当 ci=1 时,把该乘积项累积到答案中。b&1 运算可以取出 b 在二进制表示下的最低位,而 b>>1 运算可以舍去最低位,在递推的过程中将二者结合,就可以遍历 b 在二进制表示下的所有数位 ci。整个算法的时间复杂度为 O(logb)。

题目链接

代码示例

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;

int a,b,p;

int power(int a,int b,int p){
	int ans=1;
	for(;b;b>>=1){
		if(b&1) ans=(long long)ans*a%p;
		a=(long long)a*a%p;
	}
	return ans;
}

int main(){
	cin>>a>>b>>p;
	cout<<a<<"^"<<b<<" mod "<<p<<"="<<power(a,b,p)<<endl;
}

费马小定理

若 p 是质数,则对于任意整数 a,有a^{p}\equiv a(mod p)

欧拉定理

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

当 p 是质数时,φ(p)=p-1,并且只有 p 的倍数与 p 不互质。所以,只要 a 不是 p 的倍数,就有a^{p-1}\equiv 1(mod p),两边同乘 a 就是费马小定理。另外,若 a 是 p 的倍数,费马小定理显然成立

欧拉定理的推论

若正整数 a,n 互质,则对于任意正整数 b,有 a^{b}\equiv a^{b mod\varphi (n)}(mod n)

许多计数类的题目要求我们把答案对一个质数 p 取模然后输出。面对 a+b,a-b,a*b 这样的算式,可以在计算前先把 a,b 对 p 取模。面对乘方算式,根据欧拉定理的理论,可以先把底数对 p 取模、指数对 φ(p) 取模,再计算乘方。

特别地,当 a,n 不一定互质且 b>φ(n) 时,有 a^{b}\equiv a^{b mod\varphi (n)+\varphi (n)}(mod n)。这意味着即使底数和模数不互质,我们也有办法把指数的规模缩小到容易计算的范围内。上式可以通过寻找 a^{b}modn 的指数循环节证明。

扩展欧几里得算法

Bezout 算法

对于任意整数 a,b,存在一对整数 x,y,满足 ax+by=gcd(a,b)。

这里不进行具体证明,请自行查询。

Bezout 定理是按欧几里得算法的思路证明的,且上述证明同时给出了整数 x 和 y 的计算方法。这种计算方法被称为扩展欧几里得算法。

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);
    int z=x;
    x=y;
    y=z-y*(a/b);
    return d;
}

定义变量 d,x0,y0,调用 d=exgcd(a,b,x0,y0)。注意在上述代码中,x0,y0 是以引用的方式传递的。上述程序求出方程 ax + by = gcd(a,b) 的一组特解 x0,y0,并返回 a,b 的最大公约数 d。

对于更为一般的方程 ax + by = c,它有解当且仅当 d|c。我们可以先求出 ax + by = d 的一组特解 x0,y0,然后令 x0,y0 同时乘上 c/d,就得到了 ax + by = c 的一组特解 (c/d)x0,(c/d)y0。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值