1. 程式人生 > >POJ 2115

POJ 2115

C Looooops

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 33045 Accepted: 9634

Description

A Compiler Mystery: We are given a C-language style for loop of type 

for (variable = A; variable != B; variable += C)

  statement;

I.e., a loop which starts by setting variable to value A and while variable is not equal to B, repeats statement followed by increasing the variable by C. We want to know how many times does the statement get executed for particular values of A, B and C, assuming that all arithmetics is calculated in a k-bit unsigned integer type (with values 0 <= x < 2k) modulo 2k.   

Input

The input consists of several instances. Each instance is described by a single line with four integers A, B, C, k separated by a single space. The integer k (1 <= k <= 32) is the number of bits of the control variable of the loop and A, B, C (0 <= A, B, C < 2k) are the parameters of the loop.  The input is finished by a line containing four zeros. 

Output

The output consists of several lines corresponding to the instances on the input. The i-th line contains either the number of executions of the statement in the i-th instance (a single integer number) or the word FOREVER if the loop does not terminate. 

Sample Input

3 3 2 16
3 7 2 16
7 3 2 16
3 4 2 16
0 0 0 0

Sample Output

0
2
32766
FOREVER

Source

大致題意:

對於C的for(i=A ; i!=B ;i +=C)迴圈語句,問在k位儲存系統中迴圈幾次才會結束。

若在有限次內結束,則輸出迴圈次數。

否則輸出死迴圈。

解題思路:

題意不難理解,只是利用了** k位儲存系統** 的資料特性進行迴圈。

例如int型是16位的,那麼int能儲存2^16個數據,即最大數為65535(本題預設為無符號),

當迴圈使得i超過65535時,則i會返回0重新開始計數

如i=65534,當i+=3時,i=1

其實就是 i=(65534+3)%(2^16)=1

有了這些思想,設對於某組資料要迴圈x次結束,那麼本題就很容易得到方程:

x=[(B-A+2^k)%2^k] /C

即 Cx=(B-A)(mod 2^k) 此方程為 模線性方程,本題就是求X的值。

題目大意初始值是a,每一次加c ,可以對得到的值取模2^k,在值為b時結束,問最少會執行多少次,如過一直不會停FOREVER

由題中大意的到等式,假設一定會停,那麼在迴圈x次後會等於b   也就是  (a + x*c)% (2^k)= b 。

很明顯的擴充套件gcd的題目,得到等式, a + c*x - b = y*(2^k) 也就是

求解 c*x - (2^k)*y = b-a ,問有沒有整數解。

對於a*x1 + b*y1 = c ,用擴充套件gcd,

求解 a*x1 + b*y1 = gcd(a,b) = gcd(b,a%b)  = a*y2 +b* (x2-a/b*y2)

得到  x1 = y2 , y1 = ( x2 +a/b*y2 ) , 

利用這個等式,可以推到b = 0 時,那是x = 1 , y = 0 ,最大公約數為a,

在逐層返回,最終得到 a*x1 + b*y1 = gcd(a,b) 的解,

如果c%( gcd(a,b) ) == 0 那麼a*x1 + b*y1 = c有整數解,

令d = gcd(a,b),d = b / d.

最小的正整數解為x = ( x%d +d )%d.

注意:

計算n=2^k時,用位運算是最快的,1<<k (1左移k位)就是2^k

但是使用long long的同學要注意格式, 1LL<<k

使用__int64的同學要強制型別轉換 (__int64)1<<k

不然會WA

程式碼:




#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
#define LL unsigned long long
void gcd(LL a,LL b,LL &d,LL &x,LL &y)
{
    if(b==0)
    {
        d=a;
        x=1;
        y=0;
    }
    else
    {
        gcd(b,a%b,d,y,x);
        y=y-x*(a/b);
    }
    return ;
}
int main()
{ 
  LL a,b,c,d,x,y,k;
  while(cin>>a>>b>>c>>k) 
  {
  	
  	if(a==0&&b==0&&c==0&&k==0)
	  break;
	k=((LL)1)<<k;
	gcd(c,k,d,x,y);  	
  	if((b-a)%d)
  	cout<<"FOREVER"<<endl;
  	else
        {
            x = (b-a)/d*x ;
            k = k/d ;
            x = (x%k+k)%k ;
            cout<<x<<endl;
        }
  }
  return 0;
 }