POJ2115 C Looooops(扩展欧几里得)

C Looooops
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 19837 Accepted: 5301

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 < 2 k) modulo 2 k

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 < 2 k) 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


题目大意:

给定一个循环,循环的终止条件是刚好等于B的时候,其他条件会一直执行+C操作,初始值为A,现在知道机器为无符号k位,也就是数据范围为(0<=x<2^k),求是否会循环是否会终止,不能终止就输出FOREVER,其他情况输出循环了几次.

解题思路:

扩展欧几里得题目,首先我们要推出方程,kc + m * 2 ^ k = (B -A),c和k,(B-A)已知,所以c,k为系数,求一下c,k的最大公约数,根据欧几里得的定律,(B - A) mod gcd(c,k) == 0才有解,否则我们直接输出FOREVER,如果有解我们调用扩展欧几里得这个接口,可以得到一组解,要得到最后的解只要k * (B - A) / gcd(c,k)即可。扩展欧几里得详细的定理可见百度百科等其他博客。

AC代码:

#include<iostream>
#include<cstdio>

typedef long long int64;

using namespace std;

int64 gcd(int64 a,int64 b)
{
    if(b == 0)
        return a;
    return gcd(b,a%b);
}

void extend_gcd(int64 a,int64 b,int64 &x,int64 &y) //扩展欧几里得
{
    if(b == 1)
    {
        x = 1;
        y = 1 - a;
    }
    else
    {
        int64 x1,y1;
        extend_gcd(b,a % b,x1,y1);
        x = y1;
        y = x1 - x * (a / b);
    }
}

int main()
{
    int64 a,b,c,k;
    //freopen("111","r",stdin);
    while(cin>>a>>b>>c>>k && a + b + c + k)
    {
        int64 temp1,temp2;
        int64 res;
        int64 d = 1LL << k;
        //cout<<d<<endl;
        int64 g = gcd(c,d); //gcd
        //cout<<g<<endl;
        int64 left = b - a;
        if(left % g != 0)
        {
            cout<<"FOREVER"<<endl; //无解
        }
        else
        {
            c = c / g;
            d = d / g;
            extend_gcd(c,d,temp1,temp2); //kc + m * 2 ^ k = (b - a);
            /*if(temp1 < 0)
                temp1 += d; //一个周期,这样写WA,因为可能负很多*/
            res = ((temp1 * (b - a) / g % d) + d) % d; //先模掉缩小范围,要求的数乘以右边的数再除以gcd就是答案
            cout<<res<<endl;
        }
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值