http://poj.org/problem?id=2115
题目大意:
对于循环语句:
for(int i = A; i != B; i += C)
已知i、A、B、C都是无符号整数类型,给出A、B、C、k的值,所有的数都不大于2^k,计算并输出循环语句的执行次数,如果为无限次,那么直接输出"FOREVER"。
设算法执行X步,那么题目就变为求解A + CX ≡ B( mod M)(M= 2^k)。即A + CX + MY ≡ B。
CX + MY ≡ B - A(M = 2^k),就变为了求 线性同余方程,简单的套用线性同余求解算法即可。
//**********************************此处有引用
Cx=(B-A)(mod 2^k) 此方程为 模线性方程,本题就是求X的值。
下面将结合《算法导论》第2版进行简述,因此先把上面的方程变形,统一符号。
令 a=C
b=B-A
n=2^k
那么原模线性方程变形为:
ax=b (mod n)
该方程有解的充要条件为 gcd(a,n) | b ,即 b% gcd(a,n)==0
令d=gcd(a,n)
有该方程的 最小整数解为 x = e (mod n/d)
其中e = [x0 mod(n/d) + n/d] mod (n/d) ,x0为方程的最小解
那么原题就是要计算b% gcd(a,n)是否为0,若为0则计算最小整数解,否则输出FOREVER
//************************************
#include<iostream>
using namespace std;
//d=ax+by,其中最大公约数d=gcd(a,n),x、y为方程系数,返回值为d、x、y
__int64 EXTENDED_EUCLID(__int64 a,__int64 b,__int64& x,__int64& y)
{
if(b==0)
{
x=1;
y=0;
return a; //d=a,x=1,y=0,此时等式d=ax+by成立
}
__int64 d=EXTENDED_EUCLID(b,a%b,x,y);
__int64 xt=x;
x=y;
y=xt-a/b*y; //系数x、y的取值是为满足等式d=ax+by
return d;
}
int main(void)
{
__int64 A,B,C,k;
while(scanf("%I64d %I64d %I64d %I64d",&A,&B,&C,&k))
{
if(!A && !B && !C && !k)
break;
__int64 a=C;
__int64 b=B-A;
__int64 n=(__int64)1<<k; //2^k
__int64 x,y;
__int64 d=EXTENDED_EUCLID(a,n,x,y); //求a,n的最大公约数d=gcd(a,n)和方程d=ax+by的系数x、y
if(b%d!=0) //方程 ax=b(mod n) 无解
cout<<"FOREVER"<<endl;
else
{
x=(x*(b/d))%n; //方程ax=b(mod n)的最小解
x=(x%(n/d)+n/d)%(n/d); //方程ax=b(mod n)的最整数小解
printf("%I64d\n",x);
}
}
return 0;
}