P1516 青蛙的约会(exgcd以及相关结论)

非常好的题,适合入门拓展欧几里得算法以及相关结论。

结论

ax + by = gcd(a,b) = gcd(b,a%b) = bx + (a - \left \lfloor \frac{a}{b} \right \rfloor \times b) y = ay + b(x-\left \lfloor \frac{a}{b} \right \rfloor )

由此递归求解即可。

int exgcd(int a,int b,int &x,int &y){//	求解 ax + by = gcd(a,b)
	if(!b){
		x = 1,y = 0;
		return a;
	}
	int g = exgcd(b,a%b,x,y);
	int temp = x;
	x = y;
	y = temp-a/b*y;
	return g;
}

求解ax + by = c 的特解

先求解 gcd(a,b) 若 c/gcd(a,b) 不是整数 则说明无解。

证明:因为 (ax + by)/g 一定是整数 所以 c/gcd(a,b) 也要是整数。

易证:求出 ak+bl = gcd(a,b)后,令w = c/gcd(a,b),x = w*k,y = w*l。

bool liEu(int a,int b,int &x,int &y,int c){//求解ax + by = c
	int g = exgcd(a,b,x,y);
	if(c % g != 0)return 0;//无解
	int k = c/g;
	x*=k;y*=k;
	return 1;
}

最小非负整数解

有恒等式 a(x0 + k*d*b ) + b(y0 - k*d*a)。

x = x0 + db,最小的划分度,为d = 1/gcd(a,b)。

令 t = b/gcd(a,b);

则x最小值 = x0 - k*t > 0 满足取模的定义,故 min = x0 mod t,为了防一手x0是负数,所以

最小值是 (x0 mod t + t) mod t

解题思路

(m-n)x + la = x-y (mod l)

a = (m-n)

b = l

c = x-y

细节:防一手m - n < 0 则令 a = -a ,c = -c。b不用管 ,由整除性可得。

。故求解ax + by = c中x的最小整除解即可。

AC 代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int exgcd(int a,int b,int &x,int &y){//	求解 ax + by = gcd(a,b)
	if(!b){
		x = 1,y = 0;
		return a;
	}
	int g = exgcd(b,a%b,x,y);
	int temp = x;
	x = y;
	y = temp-a/b*y;
	return g;
}
bool liEu(int a,int b,int &x,int &y,int c){//求解ax + by = c
	int g = exgcd(a,b,x,y);
	if(c % g != 0)return 0;//无解
	int k = c/g;
	x*=k;y*=k;
	return 1;
}
signed main(){
	int x,y,n,m,l;
	cin>>x>>y>>m>>n>>l;
	int a = n-m;
	int b = l;
	int xx,yy;
	int c = x-y;
	if(a < 0){c = -c,a = -a;}
	if(liEu(a,b,xx,yy,c)){
		int t = b/__gcd(a,b);
		cout<<(xx%t + t)%t;
	}
	else{
		puts("Impossible");	
	}
	return 0;
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值