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

C Looooops

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 19826   Accepted: 5299

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

还是扩展欧几里得,这里注意要简化一下原来的式子

AC代码:

#include <map>
#include <set>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <cstdio>
#include <cctype>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define INF 0x7fffffff
using namespace std;

LL gcd(LL a, LL b) {
	return b == 0 ? a : gcd(b, a % b);
}

void exgcd(LL a, LL b, LL& x, LL& y) {
	if(b == 0) {
		x = 1; y = 0;
	}
	else {
		exgcd(b, a % b, y, x);
		y -= x * (a / b);
	}
}

int main() {
	LL A, B, C, k;
	while(scanf("%I64d %I64d %I64d %I64d", &A, &B, &C, &k) != EOF) {
		if(A == 0 && B == 0 && C == 0 && k == 0) break;

		if(A == B) {
			printf("0\n");
			continue;
		}

		LL a = C;
		LL b = (1LL << k);
		LL c = gcd(a, b);
		LL d = B - A;

		if(d % c != 0) {
			printf("FOREVER\n");
			continue;
		}

		a /= c;//这里要进行简化,因为可能产生多余的次数
		b /= c;
		d /= c;

		LL p, q;
		exgcd(a, b, p, q);//这里求的是最简ax+by=gcd(a,b)的一组x,y的解 

		printf("%I64d\n", (p * (d / gcd(a, b)) % b + b) % b);

	}
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-08 22:05:31

POJ - 2115 - C 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(扩展欧几里得)

辗转相除法(欧几里得算法) 时间复杂度:在O(logmax(a, b))以内 int gcd(int a, int b) { if (b == 0) return a; return gcd(b, a % b); } 扩展欧几里得算法 时间复杂度和欧几里得算法相同 int extgcd(int a, int b, int& x, int& y) { int d = a; if (b != 0) { d = extgcd(b, a % b, y, x); y -= (a / b) * x;

POJ 2115 C Loooooops 扩展欧几里得

http://poj.org/problem?id=2115 题意:给出a,b,c<=1e9,k<=32 求出p 使得 (a+pc)mod2^k=ba+pc同余b(mod2^k) 2^kx=a+pc-b -> 2^kx-pc=a-b 利用exgcd求出x,p即可 最小正整数解x=x0+(k/d)*n 通解 任意解:x同余x0 mod(k/d) x0%(k/d)显然和x0同余(k/d)x=(x0%k/d+k/d)%mod 为最小正整数解 x0%k/d为正 x显然为最小正整数解 x0%k/d

poj2115 C Looooops——扩展欧几里得

题目:http://poj.org/problem?id=2115 就是扩展欧几里得呗: 然而忘记除公约数... 代码如下: #include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long ll; ll A,B,C,k,a,b,x,y,g,s; ll gcd(ll a,ll b){return a%b?gcd(b,a%b):b;} void exgc

POJ 2142 - The Balance [ 扩展欧几里得 ]

题意: 给定 a b n找到满足ax+by=n 的x,y 令|x|+|y|最小(等时令a|x|+b|y|最小) 分析: 算法一定是扩展欧几里得. 最小的时候一定是 x 是最小正值 或者 y 是最小正值 (简单的证明应该是分x,y 符号一正一负,和x,y符号都为正来考虑) 扩欧解的方程为 ax+by = gcd(a, b) 先简化问题,等价为扩欧求的是 a'x+b'y = 1 则原方程等价为 a'x+b'y = n' (a, b, n 全部除以gcd(a, b) ) 先解x为最小正值的时候 x =

POJ - 2115C Looooops 扩展欧几里得(做的少了无法一眼看出)

题目大意&&分析: for (variable = A; variable != B; variable += C) statement;这个循环式子表示a+c*n(n为整数)==b是停止循环,题目中要求(a+c*n)%2^k=b时停止循环:所以我们可以得到一个形如ax+by=c的方程式:a+c*n=b+2^k*m:通过移项:c*x-2^k*m=b-a:可以直接套exgcd模板了: 代码: #include <iostream> using namespace std; typ

POJ 2115 C Looooops (扩展欧几里德 + 线性同余方程)

分析:这个题主要考察的是对线性同余方程的理解,根据题目中给出的a,b,c,d,不难的出这样的式子,(a+k*c) % (1<<d) = b; 题目要求我们在有解的情况下求出最小的解,我们转化一下形式. 上式可以用同余方程表示为  a + k*c = (b) % (1<<d)   <-->  k*c = (b-a) % (1<<d)(中间应该是全等号,打不出来…).这就是我们想要的同余方程,根据我的个人习惯,我把它转化为线性方程的形式. -->   c*

POJ 2142:The Balance_扩展欧几里得(多组解)

先做出两个函数的图像,然后求|x|+|y|的最小值.|x|+|y|=|x0+b/d *t |+|y0-a/d *t| 这个关于t的函数的最小值应该在t零点附近(在斜率大的那条折线的零点附近,可以观察出来).以下三种情况中,函数最小值都应该出现在B点附近./* 对于不定整数方程xa+yb=c,若 c mod Gcd(a, b)=0,则该方程存在整数解,否则不存在整数解. 上面已经列出找一个整数解的方法,在找到x * a+y * b = Gcd(a, b)的一组解x0,y0后 ,/*x * a+y

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