拓展欧几里得算法——C.一日之计在于晨

广州大学第十八届ACM大学生程序设计竞赛(同步赛)C题

谈到拓展欧几里得算法,就要从欧几里得算法裴蜀定理说起。

欧几里得算法(辗转相除法)

\(gcd(a,b)=gcd(b,a\mod b)\)

其中,当\(a=0\)时,\(\gcd(a,b)=\gcd(0,b)=b\)\(b=0\)同理

证明\(gcd(a,b)=gcd(b,a-b)\)

\(a=b+c\), \(\gcd(a,b)=d\), \(\gcd(b,c)=e\)
主要是证明\(d=e\)
\(a\mod d=0, b\mod d=0,\therefore c\mod d=0,\therefore d\leq e\)

同理,\(e\leq d,\therefore d=e\)

推广一下,相当于\(a\)不断减\(b\)直至\(a<b\),也就是直至\(a\mod b\)

int gcd(int a,int b){
	if(b==0)return a;
	return gcd(b,a%b);
}

参考:
辗转相除法的原理 _辗转相除法求最大公约数的原理是什么? (shadafang.com)

裴蜀定理(贝祖定理)

\(a,b\)是不全为0的整数,对任意整数\(x,y\),满足\(\gcd(a,b)|ax+by\),且存在整数\(x,y\),使得\(ax+by=\gcd(a,b)\)

首先证明任意整数\(x,y\),满足\(\gcd(a,b)|ax+by\)

\(\gcd(a,b)=d,\therefore a=k_{1}d,b=k_{2}d,(k_{1},k_{2})=1\)
\(ax+by=k_{1}dx+k_{2}dy=d(k_{1}x+k_{2}y)\)
\(\therefore \gcd(a,b)|ax+by\)

再证明存在整数\(x,y\),使得\(ax+by=\gcd(a,b)\)

设取整数 \(x_{0},y_{0}\) 时,\(ax+by\) 有最小正整数\(s\),即\(ax_{0}+by_{0}=s\)
\(\because ax_{0}\mod \gcd(a,b)=0\)
\(by_{0}\mod \gcd(a,b)=0\)
\(\therefore s\mod \gcd(a,b)=0\)

\(a=qs+r,(0\leq r<s)\) ---也就是把\(a\)表示成一个整数,其中\(s\)为已知,\(q\)\(r\)为未知数
\(\therefore r=a-qs=a-q(ax_{0}+by_{0})=a(1-qx_{0})+b(-qy_{0})=ax+by\) ---\(r\)可以表示成 \(ax+by\) 的形式
\(\because s\)\(ax+by\) 的最小正整数
\(\therefore r=0\)
\(\therefore a=qs\)\(a\mod s=0\)
同理,\(b\mod s=0\)
\(\therefore \gcd(a,b)\mod s=0\)

\(\because s\mod \gcd(a,b)=0,\gcd(a,b)\mod s=0,\therefore \gcd(a,b)=s\)

拓展欧几里得算法

拓展欧几里得算法实际上就是\(ax+by=\gcd(a,b)\) 的一组整数解

\(b=0\)时,\(ax+by=ax=\gcd(a,0)=a\)
此时,\(x=1,y=0\) 就是 \(ax+by=\gcd(a,b)\) 的一组整数解

\(b\neq 0\)时,
欧几里得算法可知,\(gcd(a,b)=gcd(b,a\mod b)\)
裴蜀定理可知,

\[\begin{aligned} \gcd(a,b)=ax+by \\ \gcd(b,a\mod b)=bx_{1}+(a\mod b)y_{1} \end{aligned} \]

\(\therefore x=y_{1},y=x_{1}-\frac{a}{b}y_{1}\)
利用递归,先求出下一层的\(x_{1},y_{1}\),以此类推,可以求得特解\((x_{0},y_{0})\)
构造通解

\[\begin{cases} x=x_{0}+\frac{b}{\gcd(a,b)}\ k\\ y=y_{0}-\frac{a}{\gcd(a,b)}\ k\\ \end{cases} \]

int exgcd(int a,int b,int &x,int &y){
   if(b==0){
   	x=1;y=0;
   	return a;
   }
   int x1,y1,d;
   d=exgcd(b,a%b,x1,y1);
   x=y1;y=x1-a/b*y1;
   return d;
}

\(ax+by=c\)的一组整数解

拓展欧几里得算法可知,我们可以求\(ax+by=\gcd(a,b)\)的一组整数解
那么,如果 \(c\mod gcd(a,b)=0\) ,我们只需在等式左右两边同乘\(c/\gcd(a,b)\) ,就能求得 \(ax+by=c\)的一组整数解

\(c\mod gcd(a,b)\neq0\),则无整数解。这个可以有裴蜀定理可知,证明对于不定方程 \(ax+by=m\) 其有整数解的充要条件是 \(\gcd(a,b)|m\) 即可。

例题

广州大学第十八届ACM大学生程序设计竞赛(同步赛)C题

题目

题解

根据指针的转动,可以列出 (只是大致的,未考虑加一/减一)$$t+ax=re+my$$其中,\(x\)表示顺时针或逆时针转动的次数,\(re\) 表示指针最后停的位置,\(y\) 表示转动的圈数

移动,$$ax-my=re-t$$
我们就可以根据拓展欧几里得算法求得 \(\gcd(a,m)\),以及对应的 \((x_{0},y_{0})\)
\(re-t\) 是当\(re\)取最小值时,\(\gcd(a,m)|re-t\)
\(\because re\)的范围是\([1,m]\),所以 \(re=(t-1)\%d+1\)
这样就可以求得特解\(x=x*(re-t)/d)\)(后面还要加mod)
最后再根据通解,求出 \(x\) 的最小值。

代码

#include <bits/stdc++.h>
#define int long long
#define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
using namespace std;
int exgcd(int a,int b,int &x,int &y){
    if(b==0){
        x=1;y=0;
        return a;
    }
    int x1,y1,d;
    d=exgcd(b,a%b,x1,y1);
    x=y1;y=x1-a/b*y1;
    return d;

}
void solve(){
    int t,a,m;
    cin>>t>>a>>m;
    int x,y;
    int d=exgcd(a,m,x,y);
    t=(t-1)%d+1-t; //这里就省略了re
    x=((x*t/d)%m+m)%m; //特解
    x=(x%(m/d)+(m/d))%(m/d); //通解
    cout<<min(x,m/d-x)<<endl;
}
signed main()
{
    ios;
    int T;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}
posted on 2024-03-28 20:53  菜dog的日常生活  阅读(2)  评论(0编辑  收藏  举报