Codeforces Round #592 (Div. 2) C

传送门

题意:解两个方程。

思路:首先一些简单的情况特判一下就行了。 重点解释一下 为什么搜索d次:因为在这里可以推导一下,y * d = p - w * x,那么,我们现在想得到一个合法的y是不是要让p - w * x是一个d的倍数?那么假如它现在不是d的倍数,我们是不是可以对x不断的减去,那么(p - w * x) % d的值是不是想要让它为0。而每次的变化量实际上就是w,gcd(w, d)一定是小于d的,并且gcd(w, d)乘以0~d中,一定有一个能被d给整除的。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
	ll n,p,d,w;
	cin>>n>>p>>w>>d;
	ll x1=p/w;
	if(x1>n)
	{
		cout<<-1<<endl;
		return 0;
	}
	ll x2=(p-w*x1)%w;
	if(x2==0)
	{
		cout<<x1<<" "<<0<<" "<<n-x1<<endl;
		return 0;
	}
	
	ll x3=x2/d;
	ll x4=(x2-x3*d)%d;
	if(x4==0&&x3+x1<=n)
	{
		cout<<x1<<" "<<x3<<" "<<n-(x1+x3)<<endl;
		return 0;
	}
	// wx+dy=p;
	// y=(p-wx)/d;
	for(int i=1;i<=d;i++) // 重点解释 
	{
		ll tt1=x1-i;
		ll tt2=(p-tt1*w)/d;
		if(tt1>=0&&tt2>=0&&n-(tt1+tt2)>=0&&(p-tt1*w)%d==0)
		{
			cout<<tt1<<" "<<tt2<<" "<<n-(tt1+tt2)<<endl;
			return 0;
		}
	}
	cout<<-1<<endl;
	return 0;
}

附上 扩欧方法

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll exgcd(ll a,ll b,ll &x,ll &y) // 板子
{
	if(b==0)
	{
		x=1;
		y=0;
		return a;
	}
	int g=exgcd(b,a%b,y,x);
	y-=(a/b)*x;
	return g;
}
int main()
{
	ll n,p,w,d;
	cin>>n>>p>>w>>d;
	ll x1, x2,x3;
	x1 = p/w;
	if(p%w == 0){
        if(x1<=n){
            cout<<x1<<' '<<0<<' '<<n-x1;
        }
        else cout<<-1;
        return 0;
	}
	x2 = p%w/d;
	x3 = p%w%d;
    if(x3 == 0){
        if(x1+x2<=n){
            cout<<x1<<' '<<x2<<' '<<n-x1-x2;
        }
        else cout<<-1;
        return 0;
    }
    ll x,y;
    ll dd=exgcd(w,d,x,y);
    ll c=d-x3;
    if(c%dd)
    {
        cout<<"-1"<<endl;
        return 0;
    }
    x=x*c/dd;
    ll t=d/dd;
	if(x>=0){
		x=x%t;
	}
	else{
		x=(x%t+t)%t;
	}
    if(x > x1){
        cout<<-1;
        return 0;
    }
    else{
        x1 -= x;
        x2 += (x3+x*w)/d;
        if(x1+x2<=n){
            cout<<x1<<' '<<x2<<' '<<n-x1-x2;
        }
        else cout<<-1;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值