扩展欧几里得求多组解CodeForces - 1244C

博客介绍了如何利用扩展欧几里得算法求解满足特定条件的线性同余方程,并在CodeForces的1244C题目背景下展示应用。通过求解一组解,然后通过通解公式进行二分查找,找到满足x+y<=n的解。由于可能存在数值溢出,博客中使用了__int128类型来避免这个问题,并最终成功解决了题目。
摘要由CSDN通过智能技术生成

扩展欧几里得求多组解

扩展欧几里得可以求得满足ax+by = c的一组解(这里c%gcd(a,b)要等于0);假如求得的解为(x0 , y0),G = gcd(a , b),这时我们可以发现(x0 + k(b / G) , y0 - k(a / G))就是方程的通解,我们可以通过二分、取模求最小解等等

CodeForces - 1244C

题意:给出两个方程

​ x + y + z = n

​ x * w + y * d = p

求解任一满足条件的x,y。

思路:我们可以看出z与方程无关,只用考虑x + y <= n即可;于是我们使用exgcd求出某一组解(x0 , y0),但是这个解可以含负数或加起来大于n,于是我们二分枚举通解中的k,直到遇到可行解。本题在二分过程中会爆long long,所以在中间使用了__int128,最后还是借助了测试数据过掉了这个题,网上也有多种解法值得思考

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define IO ios::sync_with_stdio(false)
#define bug cout << "-----\n"
typedef long long  ll;
typedef __int128 INT;
const int N = 100010;
int Mod = 1000000007;
void exgcd(INT a,INT b,INT &x,INT &y) {
    if(b == 0) {
        x = 1;y = 0;
        return ;
    }
    exgcd(b , a % b , x , y);
    INT x1 = x,y1 = y;
    x = y1;y = x1 - a / b * y1;
    return ;
}
int check(INT t,INT x,INT y,INT w,INT d,INT G,INT n) {
    x = x + t * (d / G);y = y - t * (w / G);
    if(x + y <= n && x >= 0 && y >= 0)return 0;
    if(x < 0) {
        return 1;
    }
    if(y < 0) {
        return -1;
    }//这里的两个if是借助了数据~~~
    if(x + y > n)return 1;
    else if(x + y <= n)return -1;
}
int main() {
    ll n,p,w,d;cin >> n >> p >> w >> d;
    INT n1 = n,p1 = p,w1 = w,d1 = d;
    INT G = __gcd(w1 , d1);
    if(p1 % G) {
        cout << -1;
        return 0;
    }
    INT x,y;
    exgcd(w1 , d1 , x , y);
    x *= (p1 / G);y *= (p1 / G);
    INT l = -1e20,r = 1e20;//l要从-1e20开始,不能从0开始
    INT mid;
    INT flag = 0;
    ll x1 = x,y1 = y;
    while(l < r){
        mid = l + r >> 1;
        int t = check(mid , x , y , w , d , G , n);
        if(t == 0) {
            flag = 1;
            break;
        }
        else if(t == -1)r = mid;
        else l = mid + 1;
    }
    if(!flag) {
        cout << -1 << endl;
    }
    else {
        x1 = x1 + (ll)mid * (d1 / G);
        y1 = y1 - (ll)mid * (w1 / G);
        cout << x1 << ' ' << y1 << ' ' << n - x1 - y1 << endl;
    }
}

欧几里得算法是一个用于计算两个整数的最大公约数的算法扩展欧几里得算法可以在得最大公约数的同时计算出满足贝祖等式 ax + by = gcd(a,b) 的整数 x 和 y,其中 a 和 b 是输入的整数。 扩展欧几里得算法可用于模反元素(逆元),其中逆元是指某个整数关于模数的乘法逆元素。 下面是我用C语言实现扩展欧几里得算法逆元的示例代码: ``` #include <stdio.h> int extended_gcd(int a, int b, int *x, int *y) { if (b == 0) { *x = 1; *y = 0; return a; } int x1, y1; int gcd = extended_gcd(b, a % b, &x1, &y1); *x = y1; *y = x1 - a / b * y1; return gcd; } int mod_inverse(int a, int m) { int x, y; int gcd = extended_gcd(a, m, &x, &y); if (gcd != 1) { printf("逆元不存在\n"); return -1; // 逆元不存在 } int inverse = (x % m + m) % m; return inverse; } int main() { int a, m; printf("请输入要逆元的整数a和模数m:"); scanf("%d %d", &a, &m); int inverse = mod_inverse(a, m); if (inverse != -1) { printf("%d关于模数%d的逆元是:%d\n", a, m, inverse); } return 0; } ``` 这是一个简单的扩展欧几里得算法逆元的实现,首先通过`extended_gcd`函数出`a`和`m`的最大公约数,并计算满足贝祖等式的整数`x`和`y`。如果最大公约数不为1,则逆元不存在。若最大公约数为1,则通过模的方式计算`x`关于模数`m`的逆元。代码中的`mod_inverse`函数用于调用`extended_gcd`函数,并处理逆元不存在的情况。最后,通过用户输入需要逆元的整数`a`和模数`m`,并输出结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值