poj 2115 Looooops 擴展歐幾里德算法

傳送門

題解轉載地址 http://www.cnblogs.com/My-Sunshine/p/4828600.html

本題和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 ;

這裏有一個坑就是 在進行位運算的時候 得用long long 還有就是在找最小的時候 需要用到同餘式

嗚嗚嗚~~~~(>_<)~~~~  我也不是很懂 直接用就對了 

代碼:

 

#include<iostream>
#define ll long long
using namespace std;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
	if(b==0)
	{
		x=1;
		y=0;
		return a;
	}
	ll g=exgcd(b,a%b,y,x);
	y-=(a/b)*x;
	return g;
}
// c*x=b-a(2^k)
int main()
{
	ll A,B,C,K;
	while(cin>>A>>B>>C>>K){
		if(A==0&&B==0&&C==0&&K==0)
		break;
		ll x,y;
		ll a=C;
		ll b=1LL<<K;
		ll c=B-A;
		ll d=exgcd(a,b,x,y);
		if(c%d){
			cout<<"FOREVER"<<endl;
		}
		else{
			x=x*c/d;
			b=b/d;
			if(x>=0)
			{
				x=x%b;
			}
			else
			{
				x=(x%b+b)%b;
			}
			cout<<x<<endl;
		}
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章