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

扩展欧几里得求多组解

扩展欧几里得可以求得满足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;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值