1. 程式人生 > >POJ 1061 - 青蛙的約會 - [exgcd求解一元線性同余方程]

POJ 1061 - 青蛙的約會 - [exgcd求解一元線性同余方程]

實力 lan typedef name 根據 sca gcd space oid

先上幹貨:

定理1:

如果d = gcd(a,b),則必能找到正的或負的整數k和l,使ax + by = d.

(參考exgcd:http://www.cnblogs.com/dilthey/p/6804137.html)

定理2:

一元線性同余方程ax ≡ n (mod b) 有解,當且僅當gcd(a,b)|n.

技術分享

也就是說,解出了ax+by=gcd(a,b),就相當於解出了ax≡n(mod b) (而且只要滿足gcd(a,b)|n,就一定有解)

定理3:

若gcd(a,b) = 1,則方程ax ≡ n (mod b)在[0, b-1]上有唯一解.

由上可知ax ≡ n (mod b) 即方程 ax + by = n,由定理1可知必然存在x,y滿足 ax + by = gcd(a,b) = 1,則必然存在nx,ny滿足 ax + by = n

則必然ax ≡ n (mod b)有解nx,由於nx+kb都是該方程的解,則在[0, b-1]上必然出現一個解。

再證唯一性:

技術分享

唯一滿足mod b = 0的條件的,只有x1 = x2

定理4:

若gcd(a, b) = d,則方程ax ≡ n (mod b)在[0, b/d - 1]上有唯一解.

技術分享

技術分享

這樣,如果我有一個方程ax ≡ n (mod b)的任意解X,那麽我先X mod (b/d),使得其在範圍[-b/d+1,b/d-1]範圍內,

再加上b/d就使其在範圍[1,2(b/d)-1]範圍內,再mod (b/d)就可以使其處在[0,b/d -1]範圍內了。

即在[0,b/d-1]範圍內的解x=[ X mod (b/d) + (b/d) ] mod (b/d).

分割線

然後正式關於題目:

題目鏈接:http://poj.org/problem?id=1061

題解:

青蛙A:a = ( x + mt ) mod L

青蛙B:b = ( y + nt ) mod L

現在要使得a=b,即( x + mt ) = ( y + nt ) (mod L),即( x - y ) + ( m - n ) t = kL;

即求最小的正整數t滿足 ( m - n ) t + KL = y - x (K=-k),即求一元線性同余方程( m - n ) x ≡ ( y - x ) (mod L) 的解;

那麽就像上面那樣,先算( m - n ) * x + L * K = gcd( m - n , L ),得到一個x的值;

然後判斷( y - x ) mod gcd( m - n , L ) == 0 ?,若能整除,則有解;

然後就只要先把x *= ( y - x ) / gcd( m - n , L ) ,再根據上面求出解集中的最小正整數即為答案;

PS.當然,最後一步求[0,b/d-1]範圍內的唯一解時,由於要mod (b/d),我們要保證b/d為正,在本題中,即保證L/d為正,故d要為正。

AC代碼:

 1 #include<cstdio>
 2 #include<algorithm>
 3 typedef long long ll;
 4 using namespace std;
 5 ll x,y,m,n,L;
 6 ll d,ans,K;
 7 void exgcd(ll a,ll b,ll &d,ll &x,ll &y){
 8     if(!b){d=a;x=1;y=0;}
 9     else {exgcd(b,a%b,d,y,x);y-=(a/b)*x;}
10 }
11 int main()
12 {
13     scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&L);
14     if(m<n)
15     {
16         swap(m,n);
17         swap(x,y);
18     }
19     exgcd(m-n,L,d,ans,K);
20     if(d==0 || (x-y)%d!=0) printf("Impossible\n");
21     else
22     {
23         ans*=(y-x)/d;
24         ans=(ans%(L/d)+(L/d))%(L/d);
25         printf("%I64d\n",ans);
26     }
27 }

PS.曾經剛開始搞ACM的時候,就因為這題是POJ第一頁上為數不多的中文題而鉆了很久,不過以當時的實力,想想就知道怎麽磕都磕不出來的,今天總算把這道題給補上了,感覺還是不錯的技術分享

POJ 1061 - 青蛙的約會 - [exgcd求解一元線性同余方程]