基础数论

基础数论

整除

最大公约数

考虑证明欧几里得算法\( \\ \gcd(a,b)=\gcd(b,a-b) \\ \gcd(a,b)=\gcd(b,a \bmod b )\)

由同余的性质,若\(d\)\(a,b\)的公约数则\(d\)定为\(b,a-b\)的公约数,若\(d\)\(b,a-b\)的公约数则\(d\)定为\(a,b\)的公约数,由\(a=b等价于a|b且b|a\)得等号左右两边约数集合相同,得证,第二行同理可得。

裴蜀定理与拓展欧几里得算法

\(a,b,c∈Z,ax+by=c\)有整数解的充要条件是$ \gcd(a,b)|c$。

必要性是显然的,若我们构造出\(ax+by=\gcd(a,b)\)的一组解则能证明充分性,即引入拓展欧几里得可证

现在要找出\(ax+by=gcd(a,b)\)的一组合法解,模仿欧几里得算法算法的方法,若我们已经求出\(bx'+(a \bmod b) y'=gcd(a,b)\)的特解\(x',y'\),则只需将此方程转化为以\(a,b\)为系数,后面的项便成了我们的特解.

\[\begin{aligned} \\bx+(a\bmod b)y &= \gcd(a,b) \\bx+(a-\left \lfloor \frac{a}{b} \right \rfloor b)y&=\gcd(a,b) \\拆开有bx+ay-\left \lfloor \frac{a}{b} \right \rfloor by&=\gcd(a,b) \\整理ay+b(x-\left \lfloor \frac{a}{b} \right \rfloor y)&=\gcd(a,b) \end{aligned} \]

最后可得\(\gcd(a,b)x+0y=gcd(a,b)\)\(x=1,y=任意\)时皆可,裴蜀定理得证。但当\(x=1,y=0\)时可证明最后的特解一定满足\(\left | x \right | \le \left | \frac{b}{2\gcd(a,b)} \right | , \left | y \right | \le \left | \frac{a}{2\gcd(a,b)} \right |\),避免爆int/long long,证明见深入浅出。
考虑对于\(ax+by=c\)的形式,仅需对\(x,y\)都乘上\(\frac{c}{\gcd(a,b)}\)即可。

对于一般解系,设\(x=x_0+k\Delta x , y = y_0-k\Delta y\)则须满足\(ak\Delta x-bk\Delta y=0\),有\(\frac{a}{\gcd(a,b)}\Delta x+\frac{b}{\gcd(a,b)}\Delta y=0\),故\(\Delta x=\frac{b}{\gcd(a,b)},\Delta y=\frac{a}{\gcd(a,b)}\)故通解形式为\(x=x_0+k\frac{b}{\gcd(a,b)} , y = y_0 - k \frac{a}{\gcd(a,b)}\)

code

#include <bits/stdc++.h>
#define int long long
using namespace std;
int exgcd(int a,int b,int &x,int &y){
	if(!b){ x=1,y=0;return a;}
	int gcd = exgcd(b,a%b,y,x);
	y-=a/b*x;
	return gcd;
}
int T,a,b,c,x,y,x_,y_,x2,y2,k,m,n;
signed main(){
	scanf("%lld",&T);
	while(T--){
		scanf("%lld%lld%lld",&a,&b,&c);
		k = exgcd(a,b,x,y),x*=c/k,y*=c/k,m=a/k,n=b/k;
		if(c%k){printf("-1\n");continue;}
		x_ = (((x-1)%n)+n)%n+1 , y_ = (((y-1)%m)+m)%m+1 , x2 = (c-b*y_)/a , y2 = (c-a*x_)/b;
		if(x2<=0) printf("%lld %lld\n" ,x_,y_);
		else printf("%lld %lld %lld %lld %lld\n",(x2-x_)/n+1,x_,y_,x2,y2);
	}
	return 0;
}

费马小定理

\(a∈Z\),p为质数且\(p\)不整除\(a\),则:$a^{p-1} \equiv 1 \pmod{p} $。

\(a^{p-1}\prod_{i=1}^{p-1} i \equiv \prod_{i=1}^{p-1} i \pmod{p}\)成立,则有$(a{p-1}-1)\prod_{i=1} i \equiv 0\pmod{p} $考虑\(1\)\(p-1\)都与p互质,所以只能是\(a^{p-1}-1\equiv 0\pmod{p}\)得证

考虑证明\(a^{p-1}\prod_{i=1}^{p-1} i \equiv \prod_{i=1}^{p-1} i \pmod{p}\) , 即证明$\prod_{i=1}^{p-1} ai \equiv \prod_{i=1}^{p-1} i \pmod{p} \(,因为\)a,i\(均与\)p\(互质,所以\)ai\(也与\)p\(互质,证明\)ai\(互不相同是容易的,故\)ai\(的集合也是一个1到\)p-1$的排列,得证。

小应用题

证明不存在正整数\(a,b\),满足\(a>1\)且对于所有正整数\(n,a^n+b\)
为素数。

考虑反证,则当\(n=1\)时,\(a+b\)为素数,当\(n=a+b\)时,由费马小定理,\(a^{a+b} \equiv a \pmod {a+b}\)\(a^{a+b}+b \equiv a+b \equiv 0 \pmod {a+b}\)

\(a^{a+b}+b\)既是\(a+b\)的倍数又是素数,矛盾,得证。

Miller-Rabin

考虑\(p\)是素数的必要条件,即取一些\(a\)判断是否有\(a^{p-1} \equiv 1 \pmod p\),正确性很高但并不充分。

引入二次探测引理,\(如果 p 是奇素数,则 𝑥^2 ≡1 \pmod p的解为 𝑥 ≡1 \pmod p 或者x \equiv - 1 \pmod p。\)

故分解\(p-1=u \times 2^t\),若在这\(t\)次平方中有除了\(1\)\(-1\)之外的数变出\(1\),则\(p\)不是素数,显然也并不充分,但取前12个质数已足够判断在\(long long\)范围内的所有数。

实现时需特判1,因为任何数的0次方是1,还有取的前12个素数及其倍数,因其不满足费马小定理的使用条件

code

#include <bits/stdc++.h>
#define int long long
using namespace std;
int pri[13]={0,2,3,5,7,11,13,17,19,23,29,31,37};
int qpow(int a,int b,int p){
	int ret = 1;
	while(b){
		if(b&1) ret = (__int128)ret*a%p;
		b>>=1 , a = (__int128)a*a%p;
	}
	return ret;
}
bool check(int a,int p){
	int d = p - 1 , t = 0;
	while(!(d&1)) d>>=1 , ++t;
	int u = qpow(a,d,p);
	if(u==1) return 1;
	while(t--){
		if(u==p-1) return 1;
		u = (__int128)u*u%p;
	}
	return 0;
}
bool Miller(int x){
	if(x<=1) return 0;
	for(int i = 1 ; i<=12 ; i++){
		if(x==pri[i]) return 1;
		if(!(x%pri[i])) return 0;
		if(!check(pri[i],x)) return 0;
	}
	return 1;
}
signed main(){
	int x;
	while(scanf("%lld",&x)==1){
		if(Miller(x)) puts("Y");
		else puts("N");
	}
	return 0;
}

逆元

即给定求\(x\)满足\(ax \equiv 1 \pmod p\)

有逆元的充要条件为\(a \perp p\)

有两种求法,一种是费马小定理,必须满足\(p\)是质数,一种是exgcd,exgcd更适用,仅需满足\(a \perp p\)
exgcd为转换为不定方程为\(ax+py=1\) , 带入求解即可。

线性求逆元

考虑递推,假设我们已经知道了\(inv_1到inv_{i-1}\),如何求出\(inv_i\),即我们需要构造出\(i^{-1} \equiv ... \pmod p\) , 一个想法是将\(p\)改为带余除法,即\(p=ki+r\) , 就有\(ki+r \equiv 0 \pmod p\) , 移项\(r \equiv -ki \pmod p\) , 对照上式同除\(ri\)\(i^{-1} \equiv -kr^{-1} \equiv -\left \lfloor \frac{p}{i} \right \rfloor inv_{p \bmod i} \pmod p\)

code
#include <bits/stdc++.h>
using namespace std;
const int N = 3e6+15;
int n,p,inv[N];
int main(){
	scanf("%d%d",&n,&p);
	inv[1]=1;
	for(int i = 2 ; i<=n ; i++) inv[i] = p-1ll*p/i*inv[p%i]%p;
	for(int i = 1 ; i<=n ; i++) printf("%d\n",inv[i]);
	return 0;
}

线性求逆元2

运用一个非常重要的性质\(\frac{\prod_{j=1}^{i-1}a_j}{\prod_{j=1}^{i}a_j} \equiv \frac{1}{a_i} \pmod p\),即我们知道了前缀积的逆元我们就知道原序列的逆元,不仅如此,将上式变一下可以得到\(\frac{1}{\prod_{j=1}^{i-1}a_j} \equiv \frac{a_i}{\prod_{j=1}^{i}a_j} \pmod p\),即前缀积的逆元倒推是非常容易的,故我们只需要先求出\(\prod_{i=1}^{n}a_i\)的逆元,然后倒推前缀积的逆元,最后求出原序列的逆元。

code
#include <bits/stdc++.h>
using namespace std;
int rd(){
	int w=0;char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while('0'<=ch&&ch<='9') w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
	return w;
}
void exgcd(int a,int b,int &x,int &y){
	if(!b){x=1,y=0;return ;}
	exgcd(b,a%b,y,x);
	y-=a/b*x;
	return ;
}
const int N = 5e6+15;
int n,p,k,a[N],sa[N],ans,res[N],y;
int main(){
	n=rd(),p=rd(),k=rd(),sa[0]=1;
	for(int i = 1 ; i<=n ; i++) a[i]=rd(),sa[i]=1ll*sa[i-1]*a[i]%p;
	exgcd(sa[n],p,res[n],y);res[n]=((res[n]%p)+p)%p;
	for(int i = n-1 ; i ; i--) res[i] = 1ll*res[i+1]*a[i+1]%p;
	for(int i = 1 , num = k; i<=n ; i++,num=1ll*num*k%p){
		int inv = 1ll*sa[i-1]*res[i]%p;
		ans = (ans+1ll*num*inv%p)%p;
	}
	printf("%d",ans);
	return 0;
}

威尔逊定理

\(p\)为素数,则有\((p-1)! \equiv -1 \pmod p\)

证明,考虑\((p-1)! \equiv -1 \equiv p-1 \pmod p\),则需证明\((p-2)! \equiv 1 \pmod p\),若

posted @ 2026-08-21 20:35  lrj3247  阅读(14)  评论(0)    收藏  举报