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;
}
}