0
点赞
收藏
分享

微信扫一扫

二元一次不定方程 (exgcd)

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

题目链接

题目描述

给定不定方程

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。
若该行对应的询问有整数解但无正整数解,包含 22 个由空格隔开的数字,依次代表整数解中,x的最小正整数值,y的最小正整数值。
否则包含 5 个由空格隔开的数字,依次代表正整数解的数量,正整数解中,x 的最小值,y 的最小值,x 的最大值,y的最大值。

题解

由线性同余方程相关定理以及裴蜀定理(贝祖定理)可知,当且仅当gcd(a,b)|c时,方程有整数解。令d = gcd(a,b), x 0 = d x c , y 0 = d y c x_0=\frac{dx}{c},y_0=\frac{dy}{c} x0=cdx,y0=cdy
a x 0 + b y 0 = d    ① ax_0 + by_0 = d\ \ ① ax0+by0=d  
由扩展欧几里得算法可以得出方程①的一组解为 x 0 , y 0 x_0,y_0 x0,y0

→ x = x 0 c d , y = y 0 c d \to x = \frac{x_0c}{d},y=\frac{y_0c}{d} x=dx0c,y=dy0c

但是这求出的仅仅是一组特殊解,显然此实还不能够满足题目的要求。这时我们就需要将x,y进行放大和缩小。假设将x增大p,将y减小q。
{ a ( x + p ) + b ( y − q ) = c a x + b y = c → p = b ∗ q a , q = a ∗ p b \begin{cases} a(x+p) + b(y-q) = c\\ ax + by = c \end{cases} \to p =\frac{b*q}{a},q=\frac{a*p}{b} {a(x+p)+b(yq)=cax+by=cp=abq,q=bap
我们想要p,q为最小的正整数,那么必然有a|b*q且b|b*q,即KaTeX parse error: Got function '\min' with no arguments as subscript at position 7: (b*q)_\̲m̲i̲n̲=\frac{a*b}{gcd…
KaTeX parse error: Got function '\min' with no arguments as subscript at position 21: …in{cases} p_\̲m̲i̲n̲ ̲= \frac{b}{d}\\…
那么下面就可以对x,y进行放大缩小:

将x变为最小正整数,同时改变y的值。

x + k p ≥ 1 → k ≥ ⌈ ( 1 − x ) ⌉ p x + kp ≥ 1\to k≥\frac{\lceil(1-x)\rceil}{p} x+kp1kp(1x)

那么x的最小正整数为x+=k*p,对应的y+=k*q(x为正整数时的最大整数解)

无整数解

​ 无整数解的情况上面已经特判,即c%d !=0

有正整数解

​ 正整数解的个数: y − 1 q + 1 \frac{y-1}{q}+1 qy1+1

​ 最小正整数解: x , y − y − 1 q ∗ q x,y-\frac{y-1}{q}*q x,yqy1q

​ 最大正整数解: x + y − 1 q ∗ p , y x+\frac{y-1}{q}*p,y x+qy1p,y

无正整数解但是有整数解

​ 最小正整数解: x , y + q ∗ ⌈ 1 − y ⌉ q x,y+q*\frac{\lceil1-y\rceil}{q} x,y+qq1y

#include<cstdio>
#include<cmath>
using namespace std;
#define int long long
int ex_gcd(int a,int b,int &x,int &y){ //扩展欧几里得算法
	if(b==0){
		x=1;
		y=0;
		return a;
	}
	int d = ex_gcd(b,a%b,x,y);
	int temp = x;
	x = y;
	y = temp - a/b*y;
	return d;
}
signed main(){
	int n;
	int a,b,c,x,y;
	scanf("%lld",&n);
	while(n--){
		scanf("%lld%lld%lld",&a,&b,&c);
		int d = ex_gcd(a,b,x,y);
		if(c%d){ //无解的情况
			printf("-1\n");
			continue;
		}
		x*=c/d,y*=c/d;
		int p = b/d,q = a/d;
		if(x<0)	k=ceil((1.0-x)/p);
		else	k=(1-x)/p;
		x+=k*p,y-=k*q;
		if(y>0){ //有正整数解的情况
			printf("%lld ",(y-1)/q+1);
			printf("%lld ",x);
			printf("%lld ",y-q*(y-1)/q);
			printf("%lld ",x+p*(y-1)/q);
			printf("%lld\n",y);
		}else{ //无正整数解的情况
			printf("%lld ",x);
			printf("%lld\n",y+ceil((1.0-y)/q));
		}
	}
	return 0;
}
举报

相关推荐

0 条评论