五指山(线性同余方程、扩展gcd)————《信息学奥赛一本通》

该博客介绍了如何运用拓展欧几里得算法解决数学问题,特别是针对线性同余方程x + bd = y (mod n) 的情况,其中大圣在佛祖的圆圈中翻筋斗寻找到达目的地的最短路径。通过求解最大公约数和线性同余方程的解,判断是否能到达目的地并找出最小翻筋斗次数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

五指山

大圣在佛祖的手掌中。

我们假设佛祖的手掌是一个圆圈,圆圈的长为 n,逆时针记为:0,1,2,…,n−1,而大圣每次飞的距离为 d。

现在大圣所在的位置记为 x,而大圣想去的地方在 y。

要你告诉大圣至少要飞多少次才能到达目的地。

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

输入格式
有多组测试数据。

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

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

输出格式
对于每组测试数据,输出一行,给出大圣最少要翻多少个筋斗云才能到达目的地。

如果无论翻多少个筋斗云也不能到达,输出 Impossible。

数据范围
2<n<10^9,
0<d<n,
0≤x,y<n
输入样例:
2
3 2 0 2
3 2 0 1
输出样例:
1
2

题解

在这里插入图片描述
上面证明 转载于 https://zhuanlan.zhihu.com/p/100567253 Pecco
——————————————————————————分割线—————————————————————

好了开始分析题意:

题目给出圆圈长为n,大圣飞的距离是d,从x到y

因此可得等式

​ x + bd = y (mod n)

=> x + bd = y + an (a、b为未知数)

=> -an + bd = y - x

这个式子中,n、d、y、x都是常数

设 gcd (n,d) 意思是n和d的最大公约数

-an + bd = gcd(n,d) 这个式子符合线性同余方程,使用拓展欧几里得算法可以求知一组解,然后我们判断 gcd(n,d) 是否可以整除 y-x ,可以整除左右两边就乘以 y − x g c d ( n , d ) \frac{y-x}{gcd(n,d)} gcd(n,d)yx 得出a、b有解时的系数,b的含义为翻筋斗云的次数,要计算 b 的最小值,因为等式

ax+by=d的通解为

{ x k = x + k ∗ b g c d ( a , b ) y k = y − k ∗ a g c d ( a , b ) \begin{cases}x_k=x+k*\frac {b} {gcd(a,b)}\\y_k=y-k*\frac {a} {gcd(a,b)}\end{cases} {xk=x+kgcd(a,b)byk=ykgcd(a,b)a ,所以 -an+bd = y-x 等式b的通解为

b k = b − k ∗ n g c d ( n , d ) b_k=b-k*\frac {n} {gcd(n,d)} bk=bkgcd(n,d)n ,因此求最小值, bmin = b mod n g c d ( n , d ) \frac {n} {gcd(n,d)} gcd(n,d)n

在这里插入图片描述

#include <iostream>
#include <cstring>
#include <algorithm>
typedef long long LL;

using namespace std;
int exgcd(LL a,LL b,LL &x,LL &y)
{
    if(b==0){
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b,a%b,y,x);
    y -= a/b*x;
    return d;
}
int main()
{
    int t; 
    cin>>t;
    while(t--){
        LL n,d,x,y;
        cin>>n>>d>>x>>y;
        LL a,b;
        int gcd = exgcd(n,d,a,b);
        if((y-x)%gcd==0){
            b *= (y-x)/gcd;
            n /= gcd;
            cout <<( b % n + n ) % n <<endl;
            
        }
        else puts("Impossible");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

葛济维的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值