关于此题参数为负的终极理解(70,80,90的可以来看看)
查看原帖
关于此题参数为负的终极理解(70,80,90的可以来看看)
53806
zjgmartin楼主2020/8/31 13:02

欧几里得算法通常情况下默认参数a,b为正数,同时gcd(a,b)也为正数,所以最好要将exgcd的参数转成正数。转正数有多种方法:其中一种是大部分题解采用的将ax+by=c的a,c取相反数,还可以将a对b取模,因为上一步的同余方程是在mod b意义下的,对等式一边取模不影响答案。

然而,即使参数为负数,exgcd以及gcd也是可以正常运算的。在数学上,通常规定gcd(-|a|,b)=gcd(|a|,b)。但是,用欧几里得算法递归求gcd时,若参数为负,则结果也可能为负,而且等于 -gcd(|a|,|b|)。在exgcd中,没必要将负的gcd取相反数,而是直接让其参与运算。但是,在求最小正数解时,答案要对b/gcd取模,取模后有可能是最小正数解或最大负数解,需要特判。(附代码)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll p1,p2,len,s1,s2,x,y;
ll exgcd(ll a,ll b)
{
	if(!b) {x=1,y=0; return a;}
	ll d=exgcd(b,a%b);
	ll z=x; x=y; y=z-a/b*y;
	return d;
}
int main()
{
	scanf("%lld%lld%lld%lld%lld",&p1,&p2,&s1,&s2,&len);
	ll gcd=exgcd(s1-s2,len),c=p2-p1; 
	if(c%gcd) {printf("Impossible\n"); return 0;}
	ll ans=(c/gcd*x%(len/gcd)+len/gcd)%(len/gcd);
	if(ans<0) ans-=len/gcd;
	printf("%lld\n",ans);
	return 0;
}
2020/8/31 13:02
加载中...