数学基础——同余问题(五指山)

问题描述

原题来自:NEFU 84

大圣在佛祖的手掌中。

我们假设佛祖的手掌是一个圆圈,圆圈的长为 n,逆时针记为:0,1,2,⋯,n−1,而大圣每次飞的距离为 d。现在大圣所在的位置记为 x,而大圣想去的地方在 y。要你告诉大圣至少要飞多少次才能到达目的地。

输入

有多组测试数据。

第一行是一个正整数 T,表示测试数据的组数;

每组测试数据包括一行,四个非负整数,分别为如来手掌圆圈的长度 n,筋斗所能飞的距离 d,大圣的初始位置 x 和大圣想去的地方 y。

注意孙悟空的筋斗云只沿着逆时针方向翻。

输出

对于每组测试数据,输出一行,给出大圣最少要翻多少个筋斗云才能到达目的地。如果无论翻多少个筋斗云也不能到达,输出 Impossible。

样例输入

2

3 2 0 2

3 2 0 1

样例输出

1

2

提示

数据范围与提示:

对于全部数据,2<n<109,0<d<n,0≤x,y<n。

问题分析

拓展欧几里得算法,实际上又是求ax+by=c这个式子中的x;本题的式子其实就是x+ad=y+bn——(a代表翻了几次跟斗,b代表着绕了多少圈)转换一下就是求ad-bn=y-x中a的解。

算法设计

利用扩展欧几里得算法,只需要套用Exgcd模板,求出最小正整数解就是了。

代码

#include<iostream>

using namespace std;

#define ll long long

ll ex_gcd(ll a,ll b,ll &x,ll &y)  //扩展欧几里得算法代码模板,可求逆元,也可以求最大公约数。

{

    if(b==0)

    {

        x=1;y=0;

        return a;

    }

    ll r=ex_gcd(b,a%b,x,y);

    ll temp=x;

    x=y;

    y=temp-(a/b)*y;

    return r;

}

int main()

{

    ll t;

    cin>>t;

    ll n,d,x,y,X,Y;

    while(t--)

    {

        cin>>n>>d>>x>>y;

        ll k=ex_gcd(d,n,X,Y);

        n=n/k;

        if((y-x)%k!=0)   //其实就是ax+by=c中c%gcd(a,b)==0才有整数解!此处c=y-x;

            cout<<"Impossible"<<endl;

        else

        {

            cout<<((X*(y-x)/k)%n+n)%n<<endl;

        }               //实际上就是X*c/gcd(a,b),出现负数的情况需要加n再模n。

    }

    return 0;

}

算法复杂度分析

       扩展欧几里得算法是递归算法,该算法的时间复杂度为O(nlogn)。

 

猜你喜欢

转载自blog.csdn.net/zxy2016011117/article/details/86489835