【一本通】五指山【exgcd】

计算大圣翻筋斗到目的地的最少次数
该博客主要介绍了如何解决一个数学问题,即计算孙悟空在佛祖手掌上翻筋斗云到达目的地的最少次数。题目设定佛祖的手掌是一个圆圈,大圣每次飞行的距离固定,目标是找出最小的翻筋斗次数。博主通过欧几里得算法求得d和n的最大公约数,并利用方程的性质找到满足条件的解,确保结果最小且为正数。代码实现中使用了C++,并给出了样例输入和输出。

Date:2022.03.31
题意描述:
大圣在佛祖的手掌中。
我们假设佛祖的手掌是一个圆圈,圆圈的长为 n,逆时针记为:0,1,2,…,n−1,而大圣每次飞的距离为 d。
现在大圣所在的位置记为 x,而大圣想去的地方在 y。
要你告诉大圣至少要飞多少次才能到达目的地。
注意:孙悟空的筋斗云只沿着逆时针方向翻。
输入格式
有多组测试数据。
第一行是一个正整数 T,表示测试数据的组数;
每组测试数据包括一行,四个非负整数,分别为如来手掌圆圈的长度 n,筋斗所能飞的距离 d,大圣的初始位置 x 和大圣想去的地方 y。
输出格式
对于每组测试数据,输出一行,给出大圣最少要翻多少个筋斗云才能到达目的地。
如果无论翻多少个筋斗云也不能到达,输出 Impossible。
数据范围
2<n<109,
0<d<n,
0≤x,y<n
输入样例:
2
3 2 0 2
3 2 0 1
输出样例:
1
2

思路:由题可得(x+k1∗d)%n==y(x+k1*d)\%n==y(x+k1d)%n==y,即d∗k1+n∗k2==y−xd*k1+n*k2==y-xdk1+nk2==yx,因此gcd(d,n)∤(y−x)gcd(d,n) \nmid (y-x)gcd(d,n)(yx)则无解,否则解为d∗k1′+n∗k2′==gcd(d,n)d*k1'+n*k2'==gcd(d,n)dk1+nk2==gcd(d,n)时的一组(k1′,k2′)(k1',k2')(k1,k2),而(k1,k2)==(y−x)/gcd(d,n)∗(k1′,k2′)(k1,k2)==(y-x)/gcd(d,n)*(k1',k2')(k1,k2)==(yx)/gcd(d,n)(k1,k2)d∗k1+n∗k2==y−xd*k1+n*k2==y-xdk1+nk2==yx的一组解。但由于要使得翻跟头数最小,即k1k1k1最小为mink1mink1mink1,我们还需操作。由方程的解特性可得:
{kk1=k1+t∗ngcd(n,d)kk2=k2−t∗dgcd(n,d)\left\{ \begin{array}{lr} kk1=k1+t*\frac{n}{gcd(n,d)} \\ kk2=k2-t*\frac{d}{gcd(n,d)} \\ \end{array} \right.{kk1=k1+tgcd(n,d)nkk2=k2tgcd(n,d)d
由此,为使得kk1kk1kk1最小为mink1mink1mink1kk1kk1kk1需要是最小正数,也就是不能再被ngcd(n,d)\frac{n}{gcd(n,d)}gcd(n,d)n除,也就相当于在保证为正数的前提下%ngcd(n,d)\%\frac{n}{gcd(n,d)}%gcd(n,d)n

代码如下:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(!b) {x=1,y=0;return a;}
    LL d=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}
int main()
{
    LL t,n,d,x,y;
    cin>>t;
    while(t--)
    {
        cin>>n>>d>>x>>y;
        LL x0,y0;
        LL dd=exgcd(d,n,x0,y0);
        if((y-x)%dd) cout<<"Impossible\n";
        else
        {
            LL k=(y-x)/dd;
            x0*=k;y0*=k;
            cout<<(x0%(n/dd)+(n/dd))%(n/dd)<<'\n';
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值