exgcd 练习题题解

exgcd原理和基础代码请看如下:

(22条消息) exgcd(扩展欧几里德算法)_zsyz_lb2003的博客-CSDN博客_exgcd

 exgcd:

        A:

 题意:

俩只青蛙试图约会(假设在赤道上),这俩只青蛙会同向且同时跳跃,让你求这俩青蛙是否有能约会成功(青蛙都有女朋友,你我却没有),成功则输出跳跃次数,否则输出"Impossible";

解题:

列出方程可知:

x+tm≡y+tn

等价于

x+tm=y+tn+kl;

移相后 t(m-n)-kl=y-x        -> t(n-m)+kl=x-y;

所以可直接用exgcd

#include<iostream>
typedef long long ll;
using namespace std;
ll gcd(ll a,ll b,ll &x,ll &y){
	if(!b){
		x=1,y=0;
		return a;
	}
	ll d=gcd(b,a%b,x,y);
	ll t=x;
	x=y;y=t-(a/b)*y;
	return d;
}
int main(){
	ll x,y,m,n,l,X,Y;
	cin>>x>>y>>n>>m>>l;
	ll len1=m-n,len2=x-y;
	if(len1<0)len1=-len1,len2=-len2;
	ll d=gcd(len1,l,X,Y);
	if(len2%d)cout<<"Impossible"<<endl;
	else{
		cout<<ll(X*(len2/d)%(l/d)+l/d)%(l/d)<<endl;
	}
}

B题:

 题意:

        和青蛙约会差不多,就是现在突然变成一个青蛙不动了,另一个青蛙沿着赤道跳(我愿称为青蛙界的舔王!可舔王蛙都有蛙等,你却没人等)。

解题:

       公式列出等于    x≡y+tn(mod  pow(2,l))

       用 kl 代替pow(2,l);

        等于 tn+ kl=x-y

        也是一个exgcd的题;

#include<iostream>
typedef long long ll;
using namespace std;
ll gcd(ll a,ll b,ll &x,ll &y){
	if(!b){
		x=1,y=0;
		return a;
	}
	ll d=gcd(b,a%b,x,y);
	ll t=x;
	x=y;y=t-(a/b)*y;
	return d;
}
ll pow(ll a,ll b){
	ll ans=1;
	while(b>0){
		if(b&1){
			ans=ans*a;
		}
		a=a*a;
		b>>=1;
	}
	return ans;
}
int main(){
	ll x,y,n,l,X,Y;
	while(1){
		cin>>x>>y>>n>>l;
		if(x==0&&y==0&&n==0&&l==0)
			break;
		l=pow(2,l);
		ll len1=n,len2=y-x;
		if(len1<0)len1=-len1,len2=-len2;
		ll d=gcd(len1,l,X,Y);
		if(len2%d)cout<<"FOREVER"<<endl;
		else{
			cout<<ll(X*(len2/d)%(l/d)+l/d)%(l/d)<<endl;
		}
		
		
	}
}

C题:

 题意:

      青蛙想过节的之前用规定的砝码为另一半买一定数量的礼物(没有青蛙我也编一个出来打击你们!青蛙都有人过节送礼物,你呢!),让你用这俩种规格的砝码求出需求最少砝码数的方案;

解题:

        假设a砝码重a,b砝码重b,礼物重c列出方程后可以得到 

        na=mb+c

        还有另一种

        nb=ma+c

        最后判断的时候需要比较俩种的砝码数量的多少;

#include<iostream>
typedef long long ll;
using namespace std;
ll gcd(ll a,ll b,ll &x,ll &y){
	if(!b){
		x=1,y=0;
		return a;
	}
	ll d=gcd(b,a%b,x,y);
	ll t=x;
	x=y;y=t-(a/b)*y;//递推;
	return d;
}
int main(){
	ll x,y,n,X,Y;
	while(1){
		cin>>x>>y>>n;
		if(x==0&&y==0&&n==0)
			break;
		ll d=gcd(x,y,X,Y);
		ll x1,y1,x2,y2;
		x1=X*n/d;
		x1=(x1%(y/d)+(y/d))%(y/d);
		y1=(n/d-(x/d)*x1)/(y/d);
		if(y1<0)
			y1=-y1;
		y2=Y*n/d;
		y2=(y2%(x/d)+(x/d))%(x/d);
		x2=(n/d-(y/d)*y2)/(x/d);
		if(x2<0)
			x2=-x2;
		if(x1+y1<x2+y2){
			cout<<x1<<" "<<y1<<endl;
		}
		else cout<<x2<<" "<<y2<<endl;
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值