数论:扩展欧几里德(洛谷P1516 青蛙的约会)
歐幾里德
基本思想:gcd(q,r)=gcd(r,q%r);
證明,設q、r的最大公因數為a,則q=xa,r=ya,xy互質
不妨設x>y(顯然如果小于會在一次gcd運算后交換)
則q%r=(x%y)*a
顯然,其與r的最大公因數仍是a
時間復雜度:接近于log級
代碼
ll gcd(ll q,ll r){if(r==0){return q;}return gcd(r,q%r); }擴展歐幾里德
對于q,r 及其最大公因數g,不定方程:
aq+br=g
必定存在無限多對整數a、b的解(證明會在下面給出)
拓展歐幾里德就是用于求出這個a與b的一對特殊值
對于遞歸轉移,有如下方程:
任務是得到ab與AB之間的轉移
又因為:
方程聯立,可解得:
(B-a)*q+(A-b-(x/y)*B)*r=0;各系數為0;
即:
問題得到解決
代碼
ll gcd(ll q,ll r){//a和b全局或傳參皆可if(r==0){b=0;a=1;return q;}ll c=gcd(r,q%r);trans=a;//中轉一下a=b;b=trans-(q/r)*b;return c; }回到前面的問題:
對于q,r 及其最大公因數g,不定方程:
aq+br=g
必定存在無限多對整數a、b的解
可以通過上面這個代碼發現:
不斷輾轉取模,q、r單調遞減
一定會達到邊界值(r==0)
那么就可以往回遞歸a與b
其值是存在且確定的
應用:求解不定方程
對于關于整數a、b的不定方程:
am+bn=w
若mn的最大公因數為g
則m和n可以分別寫為k1g和k2g(k1k2均為整數)
那么原方程可以改寫為:
ak1g+bk2g=w
顯然,當w不能整除g時,方程無解(反證易得)
當w整除g時:
w可以寫為cg,c為整數
由拓展歐幾米德可知:
ak1g+bk2g=g 恒有解
兩邊同乘c:
cak1g+cbk2g=cg
即:
cak1g+cbk2g=w
顯然這里的ca與cb就是一對整數解
綜上,我們得出結論:
對于關于整數a、b的不定方程:
am+bn=w
當且僅當w整除g時,方程有解
其中一對特殊解為ca,cb(字母定義同上)
從特殊解得到普遍解
那么如何從特殊解得到普遍解呢?
設當前已知的解為x0,y0,另一對解為x,y
那么:
兩式相減:
(x0-x)m+(y0-y)n=0;
設k1=x0-x,k2=y0-y;
那么k1,k2就是兩個解上下浮動的間隔
再移項得到
k1m=-k2n
左邊是m的倍數
右邊是n的倍數
那么不難看出,等號兩邊是m和n的公倍數
那么取m與n的最小公倍數時,k1k2取到絕對值最小的值
最小公倍數可以寫成mn/gcd(m,n)
即:
k1(min)*m=mn/gcd(m,n)
即:k1(min)=n/gcd(m,n)
同理k2(min)=m/gcd(m,n)
綜上
若一組特殊解為x0,y0
則所有解的集合是:
x0+tn/gcd(m,n)
y0+tm/gcd(m,n)
t為同一個整數;
注意x0對應的是m,換句話說就是交叉對應
代碼
(這題是洛谷P1516 青蛙的約會的題解)
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <map> #include <vector> #include <queue> #include <stack> #include <deque> #include <set> #include <string> #include <iostream> #include <climits> #define ll long long using namespace std; const int M = 500050; const int N = 500050; const ll mod = 1000000007; ll x,y,m,n,l; ll a,b,g,p,w,trans; ll gcd(ll q,ll r){if(r==0){b=0;a=1;return q;}ll c=gcd(r,q%r);trans=a;a=b;b=trans-(q/r)*b;return c; } int main() {scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&l);p=n-m;w=x-y;if(p<0){w=-w;p=-p;}g=gcd(p,l);if(w%g){printf("Impossible");return 0;} // printf("a=%lld g*l=%lld p=%lld l=%lld g=%lld b=%lld w=%lld\n",a,g*l,p,l,g,b,w);while(a<0) a+=(g*l);ll k=w/g;a*=k;if(a<0) a+=(((-a)/(l/g))+1)*(l/g);//尋找到最小正整數解a%=(l/g);printf("%lld",a);return 0; } /* */thanks for reading!
特別鳴謝:lq、qyt、wyx三位大佬對證明過程中問題的指出awa
總結
以上是生活随笔為你收集整理的数论:扩展欧几里德(洛谷P1516 青蛙的约会)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么在网上订火车票 如何在网上订火车票
- 下一篇: 桀怎么读 汉字桀怎么读