(模板题)poj 2115 C Looooops(扩展欧几里得算法)

来源:互联网 发布:mac比较好用的浏览器 编辑:程序博客网 时间:2024/06/08 15:32
C Looooops
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 23790 Accepted: 6581

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 163 7 2 167 3 2 163 4 2 160 0 0 0

Sample Output

0232766FOREVER

Source

CTU Open 2004

提示

题意:

给出A,B,C(0<=A,B,C<2^k),k(1<=k<=32)。经过几次循环才能使A=B,用for循环写成:for(i=A;B!=i;i=i+C),如果数值超出2^k,那就像电脑从0开始计数,比如k=2,运行后A变成5,那么2^2<5,5转化为1。如果永远不能跳出循环输出"FOREVER"。

思路:

首先我们可以写出Cx=(B-A+2^k)%2^k

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

之后。。。还是不能得出答案

因为有不能跳出循环这一情况,需要用扩展欧几里得算法(来源于书):

形如ax+by=c的不定方程称为二元一次不定式方程。显然(1)a=0或b=0时,方程的解确定。(2)c不是gcd(a,b)的倍数时,方程无解。

因此,只考虑ab!=0且gcd(a,b)能整除c的情况。

求最大公约数的过程:

r0=r1*q1+r2

r1=r2*q2+r3

......

rk-1=rk*qk

由倒数第二个式子往回推演,将倒数第二个式子变形得到

gcd(a,b)=rn-1*x1+rn-2*y1

联立倒数第三个式子消去rn-1得到

gcd(a,b)=rn-2*x2+rn-3*y2

以此类推,一直得到

gcd(a,b)=a*x+b*y

如此便得出了ax+by=gcd(a,b)的解,那么c是gcd(a,b)的倍数时的解也就很明显了。

那么要怎么套呢?

刚推出的方程简化为Cx=(B-A)mod2^k,这里我们称x是关于2^k的乘法逆元,表达式等价与Cx+(2^k)*y=(B-A)。

之后就好做了吧。

扩展欧几里得详解。

示例程序

Source CodeProblem: 2115Code Length: 760BMemory: 388KTime: 0MSLanguage: GCCResult: Accepted#include <stdio.h>long long x,y;long long f(long long a,long long b){    long long t,d;    if(b==0)    {        x=1;        y=0;        return a;    }    d=f(b,a%b);    t=x;    x=y;    y=t-a/b*y;    return d;}int main(){    long long k,i,d,A,B,C,a,b,c;    scanf("%lld %lld %lld %lld",&A,&B,&C,&k);    while(A!=0||B!=0||C!=0||k!=0)    {        b=1;        for(i=1;k>=i;i++)        {            b=b*2;        }        a=C;        c=B-A;        d=f(a,b);//扩展欧几里得算法        if(c%d!=0)        {            printf("FOREVER\n");        }        else        {            x=(x*c/d)%b;//完全循环一次就够了,所以有c/d            b=b/d;            x=(x%b+b)%b;//因为都是非负数所以要进行转化            printf("%lld\n",x);        }        scanf("%lld %lld %lld %lld",&A,&B,&C,&k);    }    return 0;}
                                             
0 0