总的思路:贪心
因为题目中说明了w>d,那么我们可以让y取得最小非负解,那么就可以使得x+y更小,这样就使z有解的可能性最大。
第一种解法:暴力
根据拓展欧几里得的x,y的通解。可知y的最小非负解的取值范围是0<=y<w,题中w=1e5。那么就可以直接暴力0~w的所有值,看是否满足条件。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,p,w,d;
int main()
{
    while(scanf("%lld%lld%lld%lld",&n,&p,&w,&d)!=EOF)
    {
        bool f=0;
        for(ll i=0;i<w;i++)
        {
            if((p-i*d)%w==0)
            {
                ll t=(p-i*d)/w;
                if(t+i<=n&&t>=0&&i>=0)
                {
                    f=1;
                    printf("%lld %lld %lld\n",t,i,n-t-i);
                    break;
                }
            }
        }
        if(!f)
            puts("-1");
    }
    return 0;
}

第二种解法:拓展欧几里得
如果直接用拓展欧几里得求解,因为题目中的p的取值为1e17。很容易就会超long long ,因此不能采用常规解法。
可以先求出w 和 d的最大公约数 val,先用p%val 判断方程是否有解。
如果有解,进行下一步操作:
w/=val;
d/=val;
p/=val;
把方程的系数和常数项缩小,保证解不变。
然后解此时方程w * x + d * y =p。
首先先用拓展欧几里得解方程:wx’+dy’=1。
求出此方程的 y’ 的最小非负解。
那么对于这两个方程:
1.wx’+dy’=1;
2.wx+dy=p;
基于贪心的思想,让x尽可能大,y尽可能小。把p尽可能分配给x,那么应该把p%w给y。
方程1的解要转化为方程2的解,应该要乘以一个p,但这样就不能保证y为方程最小的非负解。但可以发现,方程1左右乘以p后,y’乘上了p后,由于p可以用w和d表示,因此乘p后的y’,可以分解出一部分归入wx项中,那么就相当于直接用p%w去乘以y’,把y’转化为方程2的解。通过y的最小非负解,就可以求出x和z,只要判断满不满足条件即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,p,w,d;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    ll ans=exgcd(b,a%b,x,y);
    ll tmp=x;
    x=y;
    y=tmp-(a/b)*y;
    return ans;
}
ll cal(ll a,ll b,ll c)
{
    ll x,y;
    ll gcd=exgcd(a,b,x,y);
    if(c%gcd)
        return -1;
    x=(x%b+b)%b;
    return x;
}
int main()
{
    while(scanf("%lld%lld%lld%lld",&n,&p,&w,&d)!=EOF)
    {
        ll val=__gcd(w,d);
        if(p%val)
        {
            puts("-1");
            continue;
        }
        d/=val;
        w/=val;
        p/=val;
        ll a=cal(d,w,1);
        ll yy=a*(p%w)%w;
        ll xx=(p-yy*d)/w;
        ll zz=n-xx-yy;
        if(zz<0||xx<0)
            puts("-1");
        else
            printf("%lld %lld %lld\n",xx,yy,zz);
    }
    return 0;
}