poj 2115拓展 欧里几得

http://www.cnblogs.com/frog112111/archive/2012/08/19/2646012.html

C Looooops
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 23143 Accepted: 6357

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

给你A B C K四个变量,问你对于这样一个for循环在循环多少次之后跳出
for(int i = A ; i != B; i += c){
nothing;
}
注意这里对 i 的bit做了限制,只有k个bit,默认为无符号,也就是说 i(mod2k)

思路:

设次数为x,得到方程:

A+Cx=B(mod2k)

稍微变个形:
Cx=BA(mod2k)

于是乎形如 ax=b(modn) (1) 的方程就新鲜出炉啦,所以啊,我们只需要把在方程(1)的x的解得到,本题的解也就得到了。
关于模线性方程的通解:

形如这样的方程:

ax=b(modn)

我们可以把他转化为:
ax+n(y)=b(1)

首先判断是否有解,利用Bezout定理:若设a,b是整数,则存在整数x,y,使得 ax+by=gcd(a,b)
又因为 d=gcd(a,n) ,所以当 bmodd=0 时,即b是d的整数倍时,有解。

接着,根据 d=gcd(a,n) 我们得到这个式子:

ax+ny=d(2)

是不是感觉跟(1)有些像啊,所以咱们从这里入手,把(2)的左右同乘 b/d得到下式:
a(xb/d)+(nb/d)y=b(3)

把(1)和(3)式一对比,哎呦我去,想要知道(1)式的x,我们只需知道(3)式的x’就够了。

dakala(所以)。。。
接着求x’就好了,,,

而怎么求x’呢?答案:扩展欧几里得算法。
根据式子(2)运用 extendgcd(a,n,x,y) 算出x’。所以 x=(xb/d) 也就得到了。

令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。

但是这里又有个问题,解出来的x有可能是负的,而我们想要的是正的,所以还要进行一步操作:
x=(xmod(n/d)+n/d)mod(n/d)
有的童鞋可能要问了,这里为什么周期是n/d呢?请看(2)式,在这个式子里,如果d不等于1的话,左右两边是可以约分的,也就是说,周期并没有原来的n那么大,所以是n/d。


#include<stdio.h>
#include<string.h>
long long excgcd(long long a,long long b,long long &x,long long&y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    long long d = excgcd(b,a%b,x,y);
    long long tmp = x;
    x = y;
    y = tmp-(a/b)*y;
    return d;
}
int main()
{
    int i,j;
    long long a,b,c,d,k;
    long long C,A,B;
    while(~scanf("%lld%lld%lld%lld",&A,&B,&C,&k))
    {
        a = C;
        b = B-A;
        if(!A && !B && !C && !k)
            break;
        long long n = (long long)1<<k;
        long long x,y;
        d = excgcd(a,n,x,y);
        if(b%d!=0)
        {
            printf("FOREVER\n");
        }
        else
        {
            x=(x*(b/d))%n;
            x=(x%(n/d)+n/d)%(n/d);
            printf("%lld\n",x);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值