【模板】二元一次不定方程 (exgcd)

17 篇文章 0 订阅

题目链接

题目描述

给定不定方程

ax + by = c

若该方程无整数解,输出 −1。
若该方程有整数解,且有正整数解,则输出其正整数解的数量,所有正整数解中 x 的最小值,所有正整数解中 y 的最小值,所有正整数解中 x 的最大值,以及所有正整数解中 y 的最大值。
若方程有整数解,但没有正整数解,你需要输出所有整数解中 x 的最小正整数值, y 的最小正整数值。

正整数解即为 x, y 均为正整数的解,0 不是正整数
整数解即为 x, y 均为整数的解。
x 的最小正整数值即所有 x 为正整数的整数解中 x 的最小值,y 同理。

输入格式

第一行一个正整数 T,代表数据组数。

接下来 T 行,每行三个由空格隔开的正整数 a, b, c。

输出格式

T 行。

若该行对应的询问无整数解,一个数字 -1。
若该行对应的询问有整数解但无正整数解,包含 2 个由空格隔开的数字,依次代表整数解中,x 的最小正整数值,y 的最小正整数值。
否则包含 5 个由空格隔开的数字,依次代表正整数解的数量,正整数解中,x 的最小值,y 的最小值,x 的最大值,y 的最大值。

读入输出量较大,注意使用较快的读入输出方式。

输入输出样例

输入

7
2 11 100
3 18 6
192 608 17
19 2 60817
11 45 14
19 19 810
98 76 5432

输出

4 6 2 39 8
2 1
-1
1600 1 18 3199 30399
34 3
-1
2 12 7 50 56

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int read()	// 快读 
{
	int res = 0, f = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9'){
		if(ch == '-')
			f = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9'){
		res = res * 10 + ch - '0';
		ch = getchar();
	}
	return res * f;
}

ll exgcd(ll a, ll b, ll &x, ll &y)
{
	if(b == 0){
		x = 1;
		y = 0;
		return a;
	}
	ll d = exgcd(b, a % b, x, y);
	ll t = y;
	y = x - (a / b) * y;
	x = t;
	return d;
}

int main()
{
	int t;
	t = read();
	while(t--){
		ll a = read(), b = read(), c = read(), x, y;
		ll d = exgcd(a, b, x, y);
		if(c % d != 0)
			printf("-1\n");
		else{
			x *= c / d;
			y *= c / d;
			ll p = b / d, q = a / d, k;
			if(x < 0){	// 如果 x < 0,需要将 x 提高到最小正整数 
				k = ceil((1.0 - x) / p);
				x += p * k;
				y -= q * k;
			}
			else{	// 如果 x >= 0,需要将 x 降低到最小正整数 
				k = (x - 1) / p;
				x -= p * k;
				y += q * k;
			}
			if(y > 0){	// 有正整数解 
				printf("%lld %lld %lld %lld %lld\n", (y - 1) / q + 1, x, (y - 1) % q + 1, x + (y - 1) / q * p, y);
			}
			else{	// 有整数解但无正整数解 
				printf("%lld %lld\n", x, y + q * (ll)ceil((1.0 - y) / q));
			}
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值