拓展欧几里得算法
前言
`要理解的东西比较多,但也要背模板
提示:以下是本篇文章正文内容,下面案例可供参考
一、拓展欧几里得算法
给定 n
对正整数 ai,bi
,对于每对数,求出一组 xi,yi
,使其满足 ai×xi+bi×yi=gcd(ai,bi)
。
输入格式
第一行包含整数 n
。
接下来 n
行,每行包含两个整数 ai,bi
。
输出格式
输出共 n
行,对于每组 ai,bi
,求出一组满足条件的 xi,yi
,每组结果占一行。
本题答案不唯一,输出任意满足条件的 xi,yi
均可。
数据范围
1≤n≤105
,
1≤ai,bi≤2×109
输入样例:
2
4 6
8 18
输出样例:
-1 1
-2 1
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int exgcd(int a,int b,int &x,int &y)//其实用void就可以
{
if(!b)
{
x=1,y=0;
return a;//利用递归,求出x,y
//最后一层一定会是x=1,y=0,然后开始返回上一层,直到返回至第一层,得到原解
}
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int main()
{
int n;
cin>>n;
while(n--)
{
int a,b;
cin>>a>>b;
int x,y;
exgcd(a,b,x,y);
cout<<x<<" "<<y<<endl;
}
return 0;
}
二、线性同余方程
给定 n
组数据 ai,bi,mi
,对于每组数求出一个 xi
,使其满足 ai×xi≡bi(modmi)
,如果无解则输出 impossible。
输入格式
第一行包含整数 n
。
接下来 n
行,每行包含一组数据 ai,bi,mi
。
输出格式
输出共 n
行,每组数据输出一个整数表示一个满足条件的 xi
,如果无解则输出 impossible。
每组数据结果占一行,结果可能不唯一,输出任意一个满足条件的结果均可。
输出答案必须在 int
范围之内。
数据范围
1≤n≤105
,
1≤ai,bi,mi≤2×109
输入样例:
2
2 3 6
4 3 5
输出样例:
impossible
-3
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int main()
{
int n;
cin>>n;
while(n--)
{
int a,b,m;
cin>>a>>b>>m;
int x,y;
int d=exgcd(a,m,x,y);
if(b%d) cout<<"impossible"<<endl;
else cout<<(LL)b/d*x%m<<endl;
//证明的时候等式右侧是gcd(a,m),实际求得是b,b是gcd(a,m)的倍数,当把gcd(a,m)扩大到b时,对应的x和y也应该扩大
//题目中要求“输出答案必须在int范围之内”,而算到的x可能会溢出,根据(a*x) % m = (a * (x % m)) % m,所以保险起见输出为x % m
}
return 0;
}
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<stack>
using namespace std;
int N,M;
int exgcd(int a,int b,int &x,int &y){
if(b==0){
x = 1,y = 0;
return a;
}
int d = exgcd(b,a%b,x,y);
int tmp = x;
x = y;
y = tmp -a/b*y;
return d;
}
int main(){
int i,j,k;
cin>>N;
for(i = 1;i<=N;i++){
int a,b,m;
scanf("%d %d %d",&a,&b,&m);
int x,y;
int d = exgcd(a,m,x,y);
if(b%d==0){
int t = b/d;
printf("%d\n",((long long)x*t%(m/d)+(m/d))%(m/d));
}//这里是一个固定的模板,背会就可以//ax+my=b
//同时这个模板也可以分开写,x=x*(m/d)%m; x=(x%(m/d)+(m/d))%(m/d);//这里其实就是求最小正整数解
else
printf("impossible\n");
}
return 0;
}
A——青蛙的约会
两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。
我们把这两只青蛙分别叫做青蛙A和青蛙B,并且规定纬度线上东经0度处为原点,由东往西为正方向,单位长度1米,这样我们就得到了一条首尾相接的数轴。设青蛙A的出发点坐标是x,青蛙B的出发点坐标是y。青蛙A一次能跳m米,青蛙B一次能跳n米,两只青蛙跳一次所花费的时间相同。纬度线总长L米。现在要你求出它们跳了几次以后才会碰面。
Input
输入只包括一行5个整数x,y,m,n,L,其中x≠y < 2000000000,0 < m、n < 2000000000,0 < L < 2100000000。
Output
输出碰面所需要的跳跃次数,如果永远不可能碰面则输出一行"Impossible"
Sample
Inputcopy Outputcopy
1 2 3 4 5
4
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
ll exgcd( ll a, ll b, ll& x, ll& y ){
if( b == 0 ){
x = 1;
y = 0;
return a;
}
ll r = exgcd(b, a%b, x, y);
ll t = x;
x = y;
y = t - a/b*y;
return r;
}
int main()
{
ll a, b, c, xx, yy, m, n, l;
scanf("%lld%lld%lld%lld%lld",&xx, &yy, &m, &n, &l);
// 设次数为t, 模常数k
// (m-n)t + kl = y-x
// at+bk = c
a = m - n;
b = l;
c = yy - xx;
if( a < 0 ){
a = -a;
c = -c;
}
ll x, y;
ll d = exgcd(a, b, x, y);
if( c % d != 0 )
puts("Impossible");
else{
//这里同样与线性同余方程类似,这里的方程是ax+by=c
//所以就是x*(c/d)%b; x=(x%(b/d)+(b/d))%(b/d);//这里其实就是求最小正整数解
x=x*(c/d)%b;
x=(x%(b/d)+(b/d))%(b/d);
printf("%lld\n", x);
}
return 0;
}
B——Romantic
天空清清朗朗。
鸟儿自由翱翔。
风儿昂昂扬扬。
风吹过树梢
树干摇曳,花叶坠落。
伊人路过,而且你有伴(恼)
…yifenfei在英语课上摸鱼写的 (某lyt烂翻)
为了不被秀恩爱的喂狗粮,你准备去表白。
在HDU,每个女孩都喜欢数学。每个女孩都喜欢解数学题!所以如果你想要成功的话,需要回答对每一个女孩们提出的数学问题
今天,她们心情好,只会出一类题,如下:
每道题会告诉你两个正整数 a 和 b 。请找到最小的非负整数X和对应整数Y,以满足Xa+Yb=1。如果没有这样的答案,请打印“sorry”。
输入要求
有多组测试数据。
每组测试数据包含两个正整数 a,b (0<a, b<=2^31)
输出要求
输出最小的非负整数X和对应整数Y,如果没有答案,输出“sorry”
测试样例
Inputcopy Outputcopy
77 51
10 44
34 79
2 -3
sorry
7 -3
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int main()
{
int a,b,x,y;
while (scanf("%d%d",&a,&b)!=EOF)
{
int d=exgcd(a,b,x,y);
if (d!=1)
{
printf("sorry\n");
continue;
}
else
{
while (x>=0)
{
x-=b;
y+=a;
}
while (x<0)
{
x+=b;
y-=a;
}
printf("%d %d\n",x,y);
}
}
return 0;
}
总结
提示:这里对文章进行总结:
这类问题,构建方程是关键,然后根据方程写出最后那两行的式子,
x=x*(c/d)%b;
x=(x%(b/d)+(b/d))%(b/d);
背的东西不多,大部分都是要理解的