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

题目:

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

题意倒是很简单,就是求满足c*x-2^k*y=b-a的所有(x,y)中,x的最小非负值。

代码:

#include<iostream>
#include<stdio.h>
using namespace std;

long long x, y;

long long gcd(long long  a, long long b)
{
	if (a == 0 || b == 0)
	{
		x = (b == 0);
		y = (a == 0);
		return a + b;
	}
	long long r;
	if (a < 0)
	{
		r = gcd(-a, b);
		x *= -1;
		return r;
	}
	if (b < 0)
	{
		r = gcd(a, -b);
		y *= -1;
		return r;
	}
	if (a >= b)r = gcd(a%b, b);
	else r = gcd(a, b%a);
	y -= a / b*x;
	x -= b / a*y;
	return r;
}

int main()
{
	long long a, b, c, k, con = 1;
	while (cin >> a >> b >> c >> k)
	{
		if (k == 0)break;
		b -= a;
		k = (con << k);
		if (b == 0)cout << 0;
		else
		{
			long long g = gcd(c, -k);
			if (b%g)cout << "FOREVER";
			else cout << (x*b / g%k + k) % (k / g);
		}
		cout << endl;
	}
	return 0;
}

核心函数是拓展欧几里得函数gcd,不会的请点击打开我的博客

时间: 2024-10-28 23:27:53

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 1061 nefu 84(拓展欧几里得)

POJ1061 Language:Default 青蛙的约会 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 105002 Accepted: 20595 Description 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置.不过青蛙们都是很乐观

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

拓展欧几里得详解 及其题目 POJ 1061 2115 2142 UVA 10673 10090

最近做了一些拓展欧几里得的题目呢,嘛,从一开始的不会到现在有点感觉,总之把我的经验拿出来和大家分享一下吧. 普通的欧几里得是用于解决求两个数a,b的gcd的,但是我们知道,gcd是线性组合 { ax+by | x,y∈Z }里的最小正元素(什么?不知道怎么来的?好吧...算法导论里数论算法那一章有证明),假若我们能够把这个x和y找出来,那么可以用来解决很多问题. (以下的gcd和lcm均指(gcd(a,b)和lcm(a,b)) 首先,假设ax+by=gcd这一个方程有一个特解x*,y*.那么显然

POJ 1061 青蛙的约会(拓展欧几里得)

青蛙的约会 Time Limit: 1000MS   Memory Limit: 10000KB   64bit IO Format: %I64d & %I64u Submit Status Description 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置.不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳

数论之拓展欧几里得求解不定方程和同余方程组(一)

今天接到scy的压缩包,开始做数论专题.那今天就总结一下拓展欧几里得求解不定方程和同余方程组. 首先我们复习一下欧几里得算法: 1 int gcd(int a,int b){ 2 if(b==0) return a; 3 return gcd(b,a%b);4 } 拓展欧几里得算法: 推导过程: 给出A和B,求它们的最大公约数,并且求出x和y,满足Ax+By=gcd(A,B). 当A=0时,x=0,y=1; 当A>0时, 因为exgcd(A,B,x,y)表示Ax+By=gcd(A,B) 而且ex

bzoj4517: [Sdoi2016]排列计数--数学+拓展欧几里得

这道题是数学题,由题目可知,m个稳定数的取法是Cnm 然后剩下n-m本书,由于编号为i的书不能放在i位置,因此其方法数应由错排公式决定,即D(n-m) 错排公式:D[i]=(i-1)*(D[i-1]+D[i-2]); 所以根据乘法原理,答案就是Cnm * D(n-m) 接下来就是怎么求组合数的问题了 由于n≤1000000,因此只能用O(n)的算法求组合,这里用乘法逆元(inv[])来辅助求组合数 即 Cnm = n! / ((n-m)! * m!) = fac[n]*inv[n-m]*inv[

uva 10413 - Crazy Savages(拓展欧几里得)

题目链接:uva 10413 - Crazy Savages 题目大意:一座山有m个山洞,形成一个圈,现在有n个部落的人,每个部落一开始住在ci山洞,第2天会向后面移动pi个位置,一共会在这座山住li天.现在如果两个部落在同一个山洞相遇,则会发生战争,问说m最小时多少的时候,保证不会发生争斗. 解题思路:因为每个部落都有自己的存在时间,所以枚举m,然后枚举两个部落,判断他们有没有可能相遇. 假设在第k天: ci+k?pi=a?m???(1) cj+k?pj=b?m???(2) 由(2)-(1)得