poj 2115 Looooops

C Looooops

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 23637   Accepted: 6528

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 16
3 7 2 16
7 3 2 16
3 4 2 16
0 0 0 0

Sample Output

0
2
32766
FOREVER

Source

CTU Open 2004

分析:

a+cx%2^k=b,求解最小的x

a-b+cx%2^k=0

cx=(b-a)%2^k·························@1:典型的同余方程,通过ext_gcd求解

cx+(2^k)y=(b-a)

当且仅当 gcd(c,2^k)|(b-a)时,方程有解。

我们通过ext_gcd求得 cx+(2^k)y=gcd(b-a)的解 x,y,gcd.

把方程的两边同时/gcd*(b-a)即得到 @1式的解。

即 x = x*(b-a)/gcd。

因为我们要求最小的x,所以我们求出符合条件的x的变化周期:T:= (2^k)/gcd.

然后通过(x%T+T)%T得到最小的x,别问我为什么,因为我也不知道为什么。

#include<iostream>
#include<stdio.h>
using namespace std;
long long pow(long long k)
{
    long long ans=1;
    for(int i=0;i<k;i++)
        ans*=2;
    return ans;
}
long long ext_gcd(long long a,long long b,long long *x,long long *y)
{
    if(b==0)
    {
        *x=1,*y=0;
        return a;
    }
    long long r = ext_gcd(b,a%b,x,y);
    long long t = *x;
    *x = *y;
    *y = t - a/b * *y;
    return r;
}
int main()
{
    long long a,b,c,k;
    while(~scanf("%I64d%I64d%I64d%I64d",&a,&b,&c,&k))
    {
        if((a+b+c+k)==0) break;
        long long x,y;
        long long _gcd_ = ext_gcd(c,pow(k),&x,&y);
        if((b-a)%_gcd_)
        {
            printf("FOREVER\n");
            continue;
        }
        long long tmp_ans = x*(b-a)/_gcd_;
        long long T = pow(k)/_gcd_;/*总结一下: b/gcd是 ax+by = k*gcd中,x*k/gcd的周期*/
        long long ans = (tmp_ans%T+T)%T;
        printf("%I64d\n",ans);
    }
    return 0;
}

时间: 2024-08-25 04:05:12

poj 2115 Looooops的相关文章

POJ 2115 C Looooops(扩展欧几里得应用)

题目地址:POJ 2115 水题..公式很好推.最直接的公式就是a+n*c==b+m*2^k.然后可以变形为模线性方程的样子,就是 n*c+m*2^k==b-a.即求n*c==(b-a)mod(2^k)的最小解.(真搞不懂为什么训练的时候好多人把青蛙的约会都给做出来了,这题却一直做不出来.....这两道不都是推公式然后变形吗.....) 代码如下: #include <iostream> #include <cstdio> #include <string> #incl

【POJ 2115】 C Looooops (扩展欧几里德)

[POJ 2115] C Looooops 输入四个数a b c k 一个循环for(a;;a += c) if(a == b) break; a在k进制内循环 即0 <= a < 2^k 如果超了就返回0 即始终对2^k取余 可以得到一个方程 满足题意的话 a+c*x = b(mod 2^k) 即 c*x = b(mod 2^k) + a = (b+a)(mod 2^k) 同余 就变成求c跟2^k的逆元了 跑一遍扩欧即可 注意要变换成求最小正解 普通扩欧只是求个解 至于扩欧--看了好久...

poj 2115 C Looooops (解模线性方程)

链接:poj 2115 题意:对于C语言的循环语句for(i=A ; i!=B ;i +=C), 问在k位存储系统中循环几次才会结束. 若在有限次内结束,则输出循环次数,否则输出死循环. 注:利用了 k位存储系统的数据特性进行循环(会溢出) 例如int型是16位的,那么int能保存2^16个数据, 即最大数为65535(本题默认为无符号), 当循环使得i超过65535时,则i会返回0重新开始计数 如i=65534,当i+=3时,i=1   即 i=(65534+3)%(2^16)=1 分析:设对

POJ 2115 (模线性方程 -&gt; 扩展欧几里得)

题意: for(i=A ; i!=B ;i +=C)循环语句,问在k位操作系统中循环结束次数. 若在有则输出循环次数. 否则输出死循环. 存在这样的情况:i= 65533 :i<=2:i+= 4:时i = 2: 由模线性方程->扩展欧几里得 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> using

POJ 2115C Looooops[一元线性同余方程]

一元线性同余方程 定义: $a$,$b$是整数,$m$是正整数,形如 $ax\equiv b\,(mod\, m)$ 且$x$是未知数的同余式称作一元线性同余方程. 对于方程$ax\equiv b\,(mod\, m)$, 可以把它写成二元一次不定式$ax+my=b$.要想方程有解,必须满足$(a,m)\mid d$. 这时利用扩展欧几里得求出$ax+my=(a,m)$ 的一个特解,在乘上$b/(a,m)$就是我们所要的一个特解. 利用公式: $ax_0+my_0=d=ax+my\Rightar

POJ 2115 模线性方程 ax=b(mod n)

/* (x*c+a)%(2^k)==b →(x*c)%(2^k)==b-a 满足定理: 推论1:方程ax=b(mod n)对于未知量x有解,当且仅当gcd(a,n) | b. 推论2:方程ax=b(mod n)或者对模n有d个不同的解,其中d=gcd(a,n),或者无解. 定理1:设d=gcd(a,n),假定对整数x和y满足d=ax+by(比如用扩展Euclid算法求出的一组解). 如果d | b,则方程ax=b(mod n)有一个解x0满足x0=x*(b/d) mod n .特别的设e=x0+

poj 2115 (解单变元模线性方程)

http://poj.org/problem?id=2115 题意: 给出a,b,c,k,求x,使得(a+c*x)%(2^k)=b 限制: 0 <= a,b,c < 2^k; 1 <= k <= 32 思路: 拓展欧几里得单变元模线性方程 令 A=c;C=((b-a)%(2^k)+2^k)%(2^k);B=2^k 则这道题就化为Ax%n=B 对于Ax%B=C -> Ax+By=C -> d=Ext_gcd(A,B,x,y) //d其实为gcd(A,B) -> if

POJ 2115 C Looooops(模线性方程)

http://poj.org/problem?id=2115 题意: 给你一个变量,变量初始值a,终止值b,每循环一遍加c,问一共循环几遍终止,结果mod2^k.如果无法终止则输出FOREVER. 思路: 根据题意原题可化成c * x = b - a mod (2 ^ k),然后解这个模线性方程. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio>

POJ 2115 C Looooops(Exgcd)

[题目链接] http://poj.org/problem?id=2115 [题目大意] 求for (variable = A; variable != B; variable += C)的循环次数, 其中变量为k比特无符号整数. [题解] 题目等价于求解Cx=(B–A)(mod 2^k),利用扩展欧几里得算法可以求解该问题 [代码] #include <algorithm> #include <cstring> #include <cstdio> using name