本題和poj1061青蛙問題同屬一類,都運用到擴展歐幾裡德算法,可以參考poj1061,解題思路步驟基本都一樣。
一,題意:
對於for(i=A ; i!=B ;i+=C)循環語句,問在k位存儲系統中循環幾次才會結束。
比如:當k=4時,存儲的數 i 在0-15之間循環。(本題默認為無符號)
若在有限次內結束,則輸出循環次數。
否則輸出死循環。
二,思路:
本題利用擴展歐幾裡德算法求線性同余方程,設循環次數為 x ,則解方程 (A + C*x) % 2^k = B ;求出最小正整數 x。
1,化簡方程化為求線性同余方程標准式 ax = b (mod n);
2,擴展歐幾裡德算法求解線性同余方程 C*x = B-A (mod 2^k);
3,求出最小非負整數解。
三,步驟:
1,化簡:(A + C*x) mod 2^K = B --> C*x mod 2^k = B-A --> C*x = B-A (mod 2^k);
2,求線性同余方程 C*x = B-A (mod 2^k) , 就相當於求二元一次方程 C*x + 2^k * y = B-A
i,代入擴展歐幾裡德算法,求解方程 C*x + 2^k * y = gcd(C , 2^k) ;
ii,利用方程 C*x + 2^k * y = gcd(C , 2^k)的解 x0 以及公式 x1 = x0 * c/d 求出原方程 a*x + b*y = c 的解 x1 ;前提是:d|c (c 能被 d 整除);
3,利用周期性變化求最小的非負整數解 公式: x1 = (x1 % (b/d) + (b/d) ) % (b/d);
若方程的C*x + 2^k * y = B-A 的一組整數解為(x1 , y1),則它的任意整數解為(x1 + k * (b/d) , y1 - k * (a/d) ) ( k取任意整數 ), T = b/d就為 x1 增長的周期
i,若x1為負值,取最大的非正值:x1 = x1 % T ; 若x1為正值,以下兩步無影響;
ii,取正 :x1 = x1 + T ;
iii, 防止 i 中的 x1=0 即 ii 中的 x1=T :x1 = x1 % T ;
代碼如下:
1 #include<iostream> 2 using namespace std; 3 4 void exgcd(long long a,long long b,long long& d,long long& x,long long& y){//int& a 是定義一個存放整形變量a的地址 5 if(!b){ d=a ; x=1 ; y=0; } // d用來存儲gcd(a,b)的值 6 else { exgcd(b , a%b , d , y , x); y -= x* (a/b); } 7 } 8 9 int main(){ 10 long long A,B,C,d,x,y,T; 11 int k ; 12 while(cin>>A>>B>>C>>k){ 13 if(A==0&&B==0&&C==0&&k==0) 14 break; 15 long long n = 1LL<<k; //n = 1 * 2^k ;注意此處,若為__int64,則應該是n = (__int64)1 << k; 16 exgcd(C,n,d,x,y); 17 if( (B-A) % d != 0 ){ 18 cout<<"FOREVER\n"; 19 } 20 else { 21 x = x * (B-A) / d ; 22 T = n / d; 23 x = ( x%T + T ) % T ; 24 cout<<x<<endl; 25 } 26 } 27 return 0; 28 } View Code如發現錯誤或者有不理解的地方,請聯系我。