SGU 106 The equation(扩展欧几里德)

本文介绍了解决SGU106题目中给定方程ax+by+c=0,在限定范围内寻找所有整数解的方法。通过扩展欧几里得算法找到方程的基础解,并基于此推导出通解,最终确定满足条件的解的数量。

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

题目链接:
SGU 106 The equation
题意:
给出a,b,c,x1,x2,y1,y2求满足ax + by + c = 0且x1 <= x <= x2, y1 <= y <= y2的x,y有多少组。
分析:
扩展欧几里德的应用需要特别注意a=0,b=0,c=0的特判。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cmath>
#include <ctime>
#include <cassert>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
double eps = 1e-8;

ll a, b, c, x1, yy1, x2, y2, ans;

ll ex_gcd(ll n, ll m, ll& x, ll& y) //返回值是gcd(a, b)
{
    if(m == 0){
        x = 1, y = 0;
        return n;
    }
    ll d = ex_gcd(m, n % m, y, x);
    y -= n / m * x;
    return d;
}

void ModularLinearEquation() //模线性方程组
{
    ll x, y, x0, y0;
    ll d = ex_gcd(a, b, x, y);//求解方程ax + by = gcd(a, b)
    if(c % d) {
        printf("0\n");
        return ;
    }
    //此时的x, y是方程ax + by = gcd(a, b)的一组基础解
    a /= d, b /= d, c /= d;
    x0 = x * c, y0 = y * c; //x0, y0是ax + by = c 的一组基础解
    //a * x + b * y = c通解满足:a * (x0 + k * b) + b * (y0 - k * a) = c
    //所以:x = x0 + k * b ...①, y = y0 - k * a ...②, k ∈ Z
    //先求出满足①:x1 <= x0 + k * b <= x2的k的范围[l1, r1]
    //再求出满足②:yy1 <= y0 - k * a <= y2的k的范围[l2, r2]两者取交集即可
    //l1 = ceil((x1 - x0)/b),r1 = floor((x2 - x0)/b)
    //l2 = ceil((y0 - y2)/a), r2 = floor((y0 - yy1)/a) 
    ll l1 = (ll)ceil((double)(x1 - x0) / b);
    ll r1 = (ll)floor((double)(x2 - x0) / b);
    ll l2 = (ll)ceil((double)(y0 - y2) / a);
    ll r2 = (ll)floor((double)(y0 - yy1) / a);
    ll l = max(l1, l2), r = min(r1, r2);
    ans = (r - l + 1 < 0) ? 0 : (r - l + 1);
    printf("%lld\n", ans);
    return ;
}

int main()
{
    while(~scanf("%lld%lld%lld", &a, &b, &c)){
        scanf("%lld%lld%lld%lld", &x1, &x2, &yy1, &y2);
        int flag = 0;
        c = -c; //移项,得到方程a * x + b * y = -c
        //下面将方程的所有系数a, b, c变为非负数
        if(c < 0){
            c = -c , a = -a, b = -b;
        }
        if(a < 0){ //需要将a取相反数,相当于把x也取了相反数,所以需要将[x1, x2]的范围变为[-x2, -x1]
            ll tmpx1 = x1, tmpx2 = x2;
            x1 = -tmpx2, x2 = - tmpx1;
            a = -a;
        }
        if(b < 0){ //同理
            ll tmpyy1 = yy1, tmpy2 = y2;
            yy1 = -tmpy2, y2 = -tmpyy1;
            b = -b;
        }

        if(a == 0 && b == 0) { //0 * x + 0 * y = c
            flag = 1; 
            if(c == 0) ans = (x2 - x1 + 1) * (y2 - yy1 + 1);
            else ans = 0;
        }else if(a == 0){  // b != 0
            flag = 1;
            if(c % b == 0){ // 0 * x + b * y = c --> b * y = c
                ll tmpy = c / b;
                if(yy1 <= tmpy && tmpy <= y2) ans = x2 - x1 + 1;
                else ans = 0;
            }else ans = 0;
        }else if(b == 0) { //a != 0
            flag = 1;
            if(c % a == 0) { // a * x + 0 * y = c --> a * x = c
                ll tmpx = c / a;
                if(x1 <= tmpx && tmpx <= x2) ans = y2 - yy1 + 1;
                else ans = 0;
            }else ans = 0;
        }
        //以上处理完了a = 0或者b = 0的所有特例
        if(flag) {
            printf("%lld\n", ans);
            continue;
        }
        ModularLinearEquation();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值