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
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.
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.
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;
}