POJ 2115 C Looooops (扩展欧几里德算法求模线性方程)

本文介绍了一个特定的循环问题,即如何判断两个数A和B在A每次增加C的情况下是否会相等,并在相等时输出所需的循环次数。文章详细阐述了解决这一问题的方法,包括使用欧几里德算法求最大公约数及最小整数解的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意: 持续循环, 直到A=B停止循环, 其中每次循环A的增量为C (A+=C), 要求数据%2^k(即但A+=C, A=A%2^k, 使得数据始终在0-2^k之间), 求是否A和B会相等;

          若相等(第一次相等)则输出循环次数, 否则输出"FOREVER"`.

解:

    按照题意可设循环次数为x, 循环过程中A大于2^k的次数为y;则方程为

    (A+C*x)%2^k = B;

   即  A + C*x = B + 2^k * y

   令a = C,   b = 2^k, c = B-A;

   则上述方程可转变成:

   a*x + b*y = c;

  求解 x的最小整数解;(因为是输出第一次相等时候的循环次数, 所以求出的循环次数x一定是所有x的解中最小的正整数)

  根据欧几里德算法可求出a, b的最大公约数 gcd, 以及关于方程 a*x0+b*y0=gcd (与上面的方程不同, 注意)中的一个特解.x0, y0

  则通解方程为:

   x = x0 +  b/gcd * t;   (因为是a*x, 代入便是 a* x0 + a*b/gcd)

  y  = y0 -  a/gcd *t;   (因为是b*y,   代入便是  b*y0 - b*a/gcd)

  则要求解  a*X + b*Y = c; 只要上述通解x * c/gcd即可;(联立上述两个方程(a*x+b*y=gcd, a*X+b*Y=c 即可知道为何x*c/gcd为a*X+b*Y=c的解)

由于x求出来要求为最小整数解;故需要进行处理为:

 第一步:  x为 a*x+b*y = gcd(a, b)求出来的特解, 通过该特解去求出 a*X+b*Y = c的最小正整数解;

第二步: 将上述 x*c/gcd可得到a*X+b*Y = c的一个解X = x*c/gcd;

第三步: X =  X%(b/gcd)将解X锁定在区间(-b/gcd, b/gcd);

第四步: X = (X+b/gcd)%(b/gcd), 将解锁定在区间(0,b/gcd)中,此时为最小正整数解.

code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define inf 0x3f3f3f3f3f
using namespace std;
typedef __int64 (ll);
void exgcd(ll a, ll b, ll &g, ll &x, ll &y){
	if(b){
		exgcd(b, a%b, g, y, x);
		y = y-a/b*x;
	} else {
		x=1;
		y=0;
		g=a;
	}
	return ;
}
int main(){
	ll a, b, c, k;
	while(~scanf("%lld %lld %lld %lld", &a, &b, &c, &k), a||b||c||k){
		ll A = c;
		ll B = b-a;
		ll n = (ll)1<<k;
		ll x, y, g;
		exgcd(A, n, g, x, y);//->ax+by=g;
		if(B%g){
			printf("FOREVER\n");
		} else {
			x = (x*(B/g))%n;// ->ax+by=c; (c = g*B/g)
			x = (x%(n/g) + n/g)%(n/g);
			printf("%I64d\n", x);
		}
	}
	return 0;
	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值