POJ 1064 青蛙的约会(拓展欧几里德算法)

来源:互联网 发布:超基因优化液txt下载 编辑:程序博客网 时间:2024/06/06 09:38

一.拓展欧几里德算法

1.首先,拓展欧几里德算法是解决这样一个问题:是用来在已知a, b求解一组x,y(x,y解出来是整数),ax+by = gcd(a, b) =d(解一定存在,根据数论中的相关定理)(a,b满足不都为0).
2.算法实现

int exgcd(int a,int b,int &x,int &y){    if(b==0)    {        x=1,y=0;        return a;    }    int q=exgcd(b,a%b,y,x);    y-=a/b*x;    return q;}

二.例题

Language:
青蛙的约会
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 105408 Accepted: 20740

Description

两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。 
我们把这两只青蛙分别叫做青蛙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 Input

1 2 3 4 5

Sample Output

4
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;typedef long long ll;ll ex_gcd(ll a,ll b,ll &x,ll &y){    ll r,t;    if(!b){ x=1; y=0; return a;}    r=ex_gcd(b,a%b,x,y);    t=x;    x=y;    y=t-a/b*y;    return r;}int main(){    ll x,y,n,m,l,r;    while(scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&l)!=EOF)    {        ll xx=0,yy=0;        ll d=ex_gcd(n-m,l,xx,yy);        if((x-y)%d!=0) printf("Impossible\n");        else {            xx=xx*((x-y)/d);            r=l/d;            xx=(xx%r+r)%r;            cout<<xx<<endl;        }    }    return 0;}

题解:
列出方程,很容易就会发现用拓展欧几里德算法可以求解,但是有些部分一开始不太容易理解:
1.为什么(x-y)%d的时候无解,这个很容易理解啊,因为题目中求解的t是整数啊!!!!因为最后t=ty*(x-y)/d,ty解出来是整数,若保证(x-y)/d也是整数则t就是整数
2.为什么

            xx=xx*((x-y)/d);

            r=l/d;

            xx=(xx%r+r)%r;

首先,解出来的ty可能是负数,所以我们要加上k*b/g,可以用(xx%r+r)%r简单的完成,因为xx%r会将xx控制在(-r,r)范围内,然后通过加上r在%r就完成了。

3.为什么不是一开始的xx加上b/g呢,其实通过推到发现因为如果在最开始加上的话最后会变成(x-y)/d *b/g,因为(x-y)/d 为整数,所以是可以的,那如果无法保证(x-y)/d

为整数,那么是不是就不能这么加了呢?

Problem A

Time Limit : 1000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 19   Accepted Submission(s) : 17
Problem Description
要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。
 

Input
数据的第一行是一个T,表示有T组数据。 每组数据有两个数n(0 <= n < 9973)和B(1 <= B <= 10^9)。
 

Output
对应每组数据输出(A/B)%9973。
 

Sample Input
21000 5387 123456789
 

Sample Output
7922

//

//  main.cpp

//  HDU 1576

//

//  Created by 张嘉韬 on 16/7/18.

//  Copyright © 2016 张嘉韬. All rights reserved.

//

#include <iostream>

#include <cstdio>

#include <cstring>

using namespace std;

long long  exGcd(long long a, long long  b, long long &x, long long &y)

{

    if(b == 0)

    {

        x = 1;

        y = 0;

        return a;

    }

    long long  r = exGcd(b, a % b, x, y);

    long long  t = x;

    x = y;

    y = t - a / b * y;

    return r;

}

int main(int argc, const char * argv[]) {

    freopen("/Users/zhangjiatao/Documents/暑期训练/input.txt","r",stdin);

    int T;

    cin>>T;

    for(int t=1;t<=T;t++)

    {

        int n;

        long long B;

        cin>>n>>B;

        long long x,y,k;

        exGcd(B,9973,x,y);

        k=n*x;

        cout<<(k%9973+9973)%9973<<endl;

    }

    return 0;

}

和上题一样,同理求解


0 0
原创粉丝点击