GCD·我所理解的扩展欧几里得

题意  求不定方程 ax + by + c = 0  满足 x1 <= x <= x2, y1 <= y <= y2 的解的个数

这里弱先来预习一下扩展欧几里得算法 ( O_O ) 


欧几里得算法

先来看看欧几里得算法  也就是辗转相除法  gcd(a,b) = gcd(b, a%b);

简单的证明

a%b = r   设 d 是 a, b 的公约数即d|a && d|b

d'r = a – kb 所以 r|d  即 a, b 的公约数都是 b, r 的公约数

设 d' 是 b, r 的公约数即 d'|b && d'|r

a = kb + r  所以 d'|a  即 b, r 的公约数都是 a, b 的公约数

所以 gcd(a, b) = gcd(b, a%b);

欧几里得算法的代码

int gcd(int a, int b)
{
    if(b == 0) return a;
    return gcd(b, a % b);
}

扩展欧几里得算法

所谓扩展欧几里得算法  也就是欧几里得算法的扩展应用吧

对于二整数 a 、b,必存在整数 x 、 y 使得 ax + by = gcd(a, b),可以通过扩展欧几里得算法求出一组满足的x、y。

简单的证明

a*x1 + b*y1 = gcd(a, b) (1)

   b*x2 + a%b * y2 = gcd(b, a%b)(2)

又    gcd(a,b) = gcd(b,a%b)

所以有a*x1 + b*y1 = b*x2 + (a - a/b * b)*y2 (此处的 '/' 为向下取整除)

化简有a*x1 + b*y1 = a*y2 + b* (x2 – a/b * y2)

那么有x1 = y2,  y1 = x2 – a/b * y2;

所以我们可以通过方程(2)的一组解得到方程(1)的一组解

这样递归下去类似辗转相除法 可以发现最后总可以递归到 方程 a*x + 0*y = gcd(a, 0) (3)

而方程(3)的一组解为 x = 1, y = 0 

那么我们在递归求 gcd(a,b) 的过程中就可以一起求出方程 a*x + b*y = gcd(a, b) 的一组解

扩展欧几里得算法的代码

ll exGcd(ll a, ll b, ll &x, ll &y)
{
    if(b == 0)
    {
        x = 1, y = 0;
        return a;
    }
    ll ret = exGcd(b, a % b, x, y), t = x;
    x = y, y = t - a / b * y;
    return ret;
}

不定方程 ax + by = c 的整数通解

通过扩展欧几里得算法得到 ax + by = gcd(a, b)的一组整数解后  如何得到不定方程 ax + by = c 的整数通解呢

d = gcd(a,b) 只有 d | c 时这个方程才存在整数解   

我们可以通过扩展欧几里得算法求得方程 ax + by = d 的一组整数解 x0, y0   方程两边同时乘上 c/d  就可以得到方程 ax + by = c 的一组整数解x = x0 * c/d, y = y0 * c/d

现在我们知道了ax + by = c 的一组整数解  又怎样得到他的所有整数解呢

设 x+x' , y+y'为下一组整数解  即 a*(x + x’) + b*(y + y’) = c 

那么必须满足 ax' +by' = 0  且 x' 是满足的最小的正整数  

ax' + by' = 0  --> y' =  -((a/d) / (b/d))x'

即 x' 的最小正整数解为 x' = b/d , y' = -a/d

那么原不定方程的通解为 {(x + b/d * k , y - a/d * k) | k in Z}


SGU106 The equation

这个题就是裸的扩展欧几里得的应用了  也有一些要注意的地方  虽然题目说所有数的绝对值都是小于10^8  但是还得用64位整数  用int错了好久  还要讨论一下a, b为0的情况  a, b中有0的情况比较简单
看一下a, b都不为0的  先通过扩展欧几里得求得一组解x, y
然后找出满足 x1 <= (x + b/d * k) <= x2 && y1 <= (y - a/d * k) <= y2的 k 的个数就行
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const double eps = 1e-8;
typedef long long ll;

ll exGcd(ll a, ll b, ll &x, ll &y)
{
    if(b == 0)
    {
        x = 1, y = 0;
        return a;
    }
    ll ret = exGcd(b, a % b, x, y), t = x;
    x = y, y = t - a / b * y;
    return ret;
}

int main()
{
    ll a, b, c, d, x, y;
    ll x1, y1, x2, y2, t;

    while(~scanf("%lld%lld%lld", &a, &b, &c))
    {
        c = -c;
        ll ans = 0;
        scanf("%lld%lld%lld%lld", &x1, &x2, &y1, &y2);
        d = exGcd(a, b, x, y);
        if(d == 0)              // a == 0 && b == 0
            ans = c ? 0 : (x2 - x1 + 1) * (y2 - y1 + 1);
        else if(c % d == 0)     // ax + by = c
        {
            double lx, rx, ly, ry, l, r;
            x = c / d * x, y = c / d * y;
            if(a == 0)          //0x + by = c
                ans = (x2 - x1 + 1) * (y1 <= y && y <= y2);
            else if(b == 0)     //ax + 0y = c
                ans = (y2 - y1 + 1) * (x1 <= x && x <= x2);
            else                //ax + by = c
            {
                lx = 1.0 * (x1 - x) * d / b;
                rx = 1.0 * (x2 - x) * d / b;
                if(lx > rx) swap(lx, rx);

                ly = 1.0 * (y - y1) * d / a;
                ry = 1.0 * (y - y2) * d / a;
                if(ly > ry) swap(ly, ry);

                l = ceil(max(lx, ly) - eps);
                r = floor(min(rx, ry) + eps);
                ans = max(0.0, r - l + 1);
            }
        }
        printf("%lld\n", ans);

    }
    return 0;
}

SGU 106  The equation

There is an equation ax + by + c = 0. Given a,b,c,x1,x2,y1,y2 you must determine, how many integer roots of this equation are satisfy to the following conditions : x1<=x<=x2,   y1<=y<=y2. Integer root of this equation is a pair of integer numbers (x,y).

Input

Input contains integer numbers a,b,c,x1,x2,y1,y2 delimited by spaces and line breaks. All numbers are not greater than 108 by absolute value.

Output

Write answer to the output.

Sample Input

1 1 -3
0 4
0 4

Sample Output

4


1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可私 6信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 、可私信6博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 、可私信6博主看论文后选择购买源代码。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值