Processing math: 50%

计算机中常用基础数论知识杂谈

最大公约数

最大公约数,英文是 \(\mathcal{Greatest\ Common\ Divisor}\),简称 \(\gcd\)

两个数 \(x,y\)​ 的最大公约数,经常表示为 \(\gcd(x,y)\)​ 或者在不被误解的情况下可以表示为 \((x,y)\)​,其定义为 \(g_{\max}\ s.t.\ g|x,g|y\)​​。

同理可以定义 \(n\)​​ 个数的 \(\gcd\)

\(\mathcal{Euclid}\) 算法,也即辗转相除法

性质 \(1\):不妨 \(x\le y\)\(\gcd(x,y)=gcd(x,y\%x)\)​。

性质 \(2\)\(\gcd(x,0)=x\)

根据上述 \(2\) 个性质,即可写出代码:

ll gcd(ll x,ll y){
	if(x>y) swap(x,y);//保证大小
	if(x==0) return y;//性质2
	return gcd(y%x,x);//性质1
}

需要注意的是,辗转相除时一定要确认好大小关系,否则有可能陷入死循环。

最小公倍数

最小公倍数,英文是 \(\mathcal{Least\ Common\ Multiple}\),简称 \(\mathcal{\operatorname{lcm}}\)​。

两个数 \(x,y\)​ 的最小公倍数,经常表示为 \(\operatorname{lcm}(x,y)\)​ 或者在不被误解的情况下可以表示为 \([x,y]\)​,其定义为 \(g_{\min}\ s.t.\ x|g,y|g,g\neq 0\)​​。

需要注意,一般情况下此处的 \(x,y\) 需要大于 \(0\),但在 \(\gcd\) 中则不需要。

性质 \(3\)​:\(\gcd(x,y)\times \operatorname{lcm}(x,y)=x\times y\)​​。

因此我们可以直接使用这个性质利用上面的 \(\gcd\) 函数计算两数 \(\operatorname{lcm}\)​​。

同理可以定义 \(n\) 个数的 \(\operatorname{lcm}\)

裴蜀定理

\(\mathcal{Bez\acute{o}ut}\)​ 定理

即,对 \(n\)​ 个整数 \(a_1,a_2,\dots a_n\)​ ,不定方程 \(a_1x_1+a_2x_2+\dots +a_nx_n=c\) 有整数解 \((x_1,x_2\dots x_n)\)​ 的充要条件是 \(\gcd(a_1,a_2,a_3\dots a_n)|c\)

证明略。

扩展 \(\mathcal{Euclid}\) 算法

根据裴蜀定理,可以求解 \(2\) 元的不定方程。

由于也是通过辗转相除求解故称为扩展 \(\mathcal{Euclid}\)​ 算法,被称为 \(\operatorname{exgcd}\)

代码:

ll exgcd(ll a,ll b,ll &tx,ll &ty){
    if(b==0){tx=1;ty=0;return a;}
    ans=exgcd(b,a%b,tx,ty);
    ll tp=tx;tx=ty;ty=tp-a/b*ty;
    return ans;
}

高斯消元

\(\mathcal{Gauss-Jordan\ Elimination}\),高斯消元的全名。

主要用于解决 线性方程组 的解,可以判断无解,有无穷多组解的情况。

线性方程组 形如:

\(\begin{cases}a_{1,1}x_1+a_{1,2}x_2+\dots +a_{1,n}x_n=a_{1,n+1}\\\dots\\a_{n,1}x_1+a_{n,2}x_2+\dots +a_{n,n}x_n=a_{n,n+1}\end{cases}\)

算法的主要部分即两两消元。

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++)
			scanf("%lf",&a[i][j]);
		scanf("%lf",&a[i][0]);
	}//输入部分
	int del=0;
	for(int i=1;i<=n;i++){
		int now=0;
		for(int j=del+1;j<=n;j++)
			if(fabs(a[j][i])>eps){
				now=j;
				break;
			}
		if(!now) continue;//没有找到该项系数不为0的方程。
		del++;
		for(int j=0;j<=n;j++) swap(a[now][j],a[del][j]);
		for(int j=1;j<=n;j++){
			if(j==del) continue;
			double rate=a[j][i]/a[del][i];
			for(int k=0;k<=n;k++) a[j][k]-=a[del][k]*rate;//加减消元
		}
	}
    //del 代表的是已经确定下来的x数量,以上就是消元的过程
	if(del==n) for(int i=1;i<=n;i++) printf("x%d=%.2lf\n",i,a[i][0]/a[i][i]);
	else{
		bool flag=1;
		for(int i=del+1;i<=n;i++)
			if(fabs(a[i][0])>eps){
				flag=0;
				break;
			}
		if(flag) puts("0");
		else puts("-1");
	}
	return 0;
}

本文作者:Rolling_Code

本文链接:https://www.cnblogs.com/RollingCode/p/qwq.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @ 2021-09-17 06:56  Rolling_Code  阅读(185)  评论(0)    收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起