[数学基础] 6 初等数论四大定理

初等数论四大定理

1. 威尔逊定理

(1) 结论

当且仅当p为素数时,(p1)!1(modp)

(2) 证明

充分性:若p不为素数,则(p1)!1(modp)

  • p=4时,显然(p1)!62(modp)

  • p>4

    • p为完全平方数,则k,使得p=k2,由于p>4,故k>2,2k<p(p1)!n(k×2k)2n×k20(modp)
    • p不是完全平方数,则a,b,ab,使得ab=p,则(p1)!nab0(modp)

必要性:若p为素数,则一定有(p1)!1(modp)

p=2时,结论显然成立。

p为奇素数,取集合A={1,2,3,..,p1}A构成模p乘法的简化剩余系,即iA,jA,使得i×j1(modp)

证明:因为A构成模p乘法的取值的集合了(除了0),所以这个结论肯定成立。

那么,这p1个数是不是两两配对的呢?首先,由同余的运算法则,可以得到一定没有ijik(modp),jk的情况,那么它一定是两个一对,或者单独一个的情况。考虑x21(modp),解得x1(modp),或者xp1(modp),那么其余则两两配对。因此(p1)!1×(p1)1(modp),得证。

(5)例题

可以看下它的考察方式:UVA1434 YAPTCHA,主要就是欧拉筛+威尔逊定理+前缀和

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

int n, cnt;
const int N = 3e6 + 20;
bool st[N];
int p[N], pre[N];

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

void init(){
	Euler(N - 1);
	for (int i=1;i<N;++i){
		int x = 0;
		if (i > 7 && (i - 7) % 3 == 0 && !st[i]){
			x = 1;
		}
		pre[i] = pre[i - 1] + x;
	}
}

int main(void){
	init();
	int t;
	scanf("%d", &t);
	while (t--){
		scanf("%d", &n);
		printf("%d\n", pre[n * 3 + 7]);
	}
	return 0;
}

2. 欧拉定理

(1) 结论

m是一个大于1的整数,且满足条件(a,m)=1,则我们有

aφ(m)1(modm)

(2) 证明

引理1:m是一个大于1的整数,a是一个整数且满足(a,m)=1,如果B={b1,b2,..,bφ(m)}是模m的一个简化剩余系,则B={ab1,ab2,..,abφ(m)}也是模m的一个简化剩余系。

证明:由于从B中取出任何一个正整数bi,都有(bi,m)=1。又(a,m)=1,可以得到在B中任意取出一个整数abi,都有(abi,m)=1。那么,现在利用反证法,假设在B中存在两个整数abk,abλ1k<λφ(m),使得:abkabλ(modm)成立。

(a,m)=1,故bkbλ(modm),由于bk,bλ是简化剩余系的元素,因此不可能模m同余,所以同余等式不可能成立,得证。

下面正式的证明欧拉定理。

考虑模m的最小正缩系A,即A={1,a2,...,aφ(m)},是不大于m且和m互质的全体正整数,令r1是一个整数,满足条件:a×1r1(modm),r1[0,m1]

ri(其中i=2,..,φ(m))是一个整数,满足条件:aairi(modm),ri[0,m1]

则我们有ar1(modm),aa2r2(modm),..,aaφ(m)rφ(m)(modm)

由于A是模m的一个简化剩余系,并且(a,m)=1,因此R={r1,r2,..,rφ(m)}也是一个简化剩余系,并且和A至少在次序上可能有不同,故得到i=1φ(m)ri=i=1φ(m)ai

因此i=1φ(m)(a×ai)i=1φ(m)ai(modm)

aφ(m)1(modm)

(3) 推论

欧拉降幂:
  • AbAbmodφ(m)(modm)

证明:设b=k×φ(m)+r,则r=bmodφ(m)

AbAr×(Aφ(m))kAr(modm),得证。

3. 费马小定理

(1) 结论

事实上,费马小定理就是欧拉定理的一种特殊情况。

如果p为质数,pa,则我们有ap11(modp)

(1) 证明

由于p为质数,因此φ(p)=p1,取欧拉定理中m=p,即得到费马小定理。

需要注意的是,mN+,aZ,使得ma,这里m不是素数,使得am11(modm),即费马小定理的逆定理不成立。比如,10241(mod341)2340(210)34(1024)341(mod341),而341=11×31,不是素数。

(2) 推论

明显的,当p为质数,且pa时,ap2a1(modp),由此就可以求得在模p意义下的乘法逆元。

欧拉定理和费马定理很难单独考察,大部分都是作为解题的一个步骤出现。

4. 中国剩余定理

1) 中国剩余定理(crt)

定理

有一元线性同余方程组(S)如下。

(S):{xa1 (modm1)xa2 (modm2)...xan (modmn)

假设整数m1,m2,...,mn两两互质,则对任意的整数a1,a2,...,an,方程组(S)有解,并且通解可以用如下方式构造得到:

M=i=1nmiMi=Mmi,设ti=Mi1,为Mi在模mi意义下的Mi的模mi乘法逆元。

方程组(S)的通解形式为x=a1t1M1+a2t2M2+...+antnMn+kM=kM+i=1naitiMi,kZ

在模M的意义下,方程组(S)只有一个解:x=(i=1naitiMi)modM

namo 首先解的每一项,都是可以求出来的,ti也可以通过扩展欧几里得算法求出。然后再来小小的证明下!

证明

  1. 首先证明x是方程组(S)的一个解。

对于解的每一项,可以看出aitiMiai×1ai(modmi )

aitiMi0 (modmj )j[1,n],ji

因此,x满足x=aitiMi+jiajtjMjai+ji0ai (modmi),  i[1,n]

x是方程组的一个解。

  1. 然后证明在模M的意义下,方程组(S)只有一个解。

假设x1,x2都是方程组(S)的解,那么x1x20 (modmi),i[1,n]

m1,m2,...,mn两两互质,这说明M|(x1x2),所以方程组(S)的任何两个解之间必然相差M的整数倍,所以方程组所有的解的集合就是{kM+i=1naitiMi;kZ}

所以在模M的意义下,方程组(S)只有一个解。

  • 代码:
int n;
const int N = 10 + 5;
int A[N], B[N];

ll mod(ll a, ll b){
	return (a % b + b) % b;
}

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(void){
	scanf("%d", &n);
	ll M = 1, res = 0, ti, y;
	for (int i=1;i<=n;++i){
		scanf("%d%d", &A[i], &B[i]);
		M = M * A[i];
	}
	for (int i=1;i<=n;++i){
		ll Mi = M / A[i];
		exgcd(Mi, A[i], ti, y);
		res = mod(res + Mi * ti * B[i], M);
	}
	printf("%lld\n", res);
	
	return 0;
}

2) 扩展中国剩余定理(excrt)

(rxz的题解写的太好了,受益良多QAQ,他讲的东西真的都是清晰细致又简单 但是因为他用python所以不推mod 岂可修)

https://www.luogu.com.cn/blog/blue/kuo-zhan-zhong-guo-sheng-yu-ding-li

这里自己再重新推导一遍。

修改条件,使得m1,m2,...,mn不再两两互质,此时应该如何求方程组的解?

(S):{xa1 (modm1)xa2 (modm2)...xan (modmn) x={kM+i=1naitiMi;kZ}

互质条件不满足时,ti不存在。(回忆逆元的定义,只有当(b,m)=1时才存在b1(modm)),那么不能利用公式时,只能尝试去不断的合并方程,直到n个方程仅剩下一个,再使用扩展欧几里得算法求解唯一的同余方程。那么,如何将两个方程等价的变换为一个方程呢?考虑如下情况:

{xa1(modm1)xa2(modm2)

此方程组等价于x=k1m1+a1=k2m2+a2

移项后,得k1m1k2m2=a2a1

a=m1,b=m2,m=a2a1,方程就变成了我们最熟悉的不定方程。那么,记d=(m1,m2),求是否有x,y,满足ax+by=d。求解的步骤即是:先用裴蜀定理判断是否有解,再用扩展欧几里得算法求解(系)。则k1=x×a2a1d,k2=y×a2a1d,这就是方程的一组特解。为了避免数据溢出,可以让k1:=k1modm2d(具体证明见裴蜀定理),那么,x=a1+k1m1,就求出来了两个方程的特解。设这个特解为r,那么它的通解就是{r+k×LCM,kZ},那么,就可以合并两个同余方程啦!

xr (modLCM)

这样不断合并,直到只剩下一个方程,解出答案即可。注意,中间非常容易数据溢出!即使是long long!所以最好直接用一个mul函数,一边做乘法一边做模运算。


横线中的这段是rxz的证明,嘛嘛,就相当于方程ax+by=d两边÷d,结果是一样的。

那么,记d=(m1,m2)p1=m1d,p2=m2d,易得(p1,p2)=1

方程可被写为这样的形式:k1p1k2p2=a2a1d

由于当d|(a2a1)时,方程才有解,因此右边的式子为整数。接着按照exgcd的流程走,我们求这个方程的解

λ1p1+λ2p2=1,则{k1=a2a1d×λ1k2=a2a1d×λ2

将结果代入方程,得x=a1+k1m1=a1+a2a1dλ1m1

这个x就是方程的一个特解。

那么,进一步的,如何求出整个解系呢?

定理:若有特解x,令LCM=lcm(m1,m2),则{xa1(modm1)xa2(modm2) 的通解为x={k×LCM+x;kZ}

该定理的证明和CRT的证明完全相同。好累,我不想重抄一遍所以就这样吧


  • 代码:
int n;
const int N = 1e5 + 10;
ll a1, m1, a[N], m[N], res;

ll mul(ll a, ll b, ll M){
    ll res = 0;
    while (b > 0){
        if (b & 1) res = (res + a) % M;
        a = (a + a) % M;
        b >>= 1;
    }
    return res;
}

ll merge(ll a2, ll m2){
    ll x, y, M, c = mod(a2 - a1, m2);
    ll d = exgcd(m1, m2, x, y);
    if (c % d){
        return -1;
    }
    M = (m1 / d * m2);
    ll k1 = mod(mul(x, c / d, m2 / d), m2 / d);
    ll r = mod(k1 * m1 + a1, M);
    a1 = r, m1 = M;
    return r;
}

int main(void){
    scanf("%d", &n);
    scanf("%lld%lld", &m1, &a1);
    if (n == 1){
        printf("%lld\n", mod(a1, m1));
        return 0;
    }
    for (int i=1;i<n;++i){
        scanf("%lld%lld", &m[i], &a[i]);
    }
    for (int i=1;i<n;++i){
        res = merge(a[i], m[i]);
        if (res < 0) break;
    }
    printf("%lld\n", res);
    return 0;
}
posted @   跳岩  阅读(363)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示