拓展欧几里得算法

拓展欧几里得算法


前言

`要理解的东西比较多,但也要背模板


提示:以下是本篇文章正文内容,下面案例可供参考

一、拓展欧几里得算法

给定 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);
背的东西不多,大部分都是要理解的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值