计算机中常用基础数论知识杂谈
最大公约数
最大公约数,英文是 \(\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 中国大陆许可协议进行许可。
【推荐】博客园的心动:当一群程序员决定开源共建一个真诚相亲平台
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】Flutter适配HarmonyOS 5知识地图,实战解析+高频避坑指南
【推荐】开源 Linux 服务器运维管理面板 1Panel V2 版本正式发布
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步