牛客练习赛60 D 斩杀线计算大师

LINK:斩杀线计算大师

给出a,b,c三个值 求出 ax+by+cz=k的x,y,z的正整数解 保证一定有解。

考虑两个数的时候 ax+by=k 扩展欧几里得可以解决。

三个数的时候 一个暴力的想法暴力枚举c的系数z 然后进行计算扩欧 期望复杂度是过不了的 但是数据保证有解那么就很容易通过了。

考虑 (a,b)|k-cz 设g=(a,b) Tg=k-cz 对于这个式子 我们发现z越小那么tg越大 那么a和b更容易是正整数 且g|k-sz是ax+by=k-cz的必要条件。

所以我们解出 Tg=k-cz这个式子的答案并且让z尽可能的小 可以发现此时一定有解 且构造出的解cz一定比其他cz更优于满足答案。

所以两次扩展欧几里得解决。

const ll MAXN=1010;
ll a,b,c,k;
ll x,y;
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll exgcd(ll a,ll b)
{
	if(!b){x=1;y=0;return a;}
	ll w=exgcd(b,a%b);
	ll z=x;x=y;y=z-a/b*y;
	return w;
}
signed main()
{
	freopen("1.in","r",stdin);
	get(a);get(b);get(c);get(k);
	ll g=gcd(a,b);
	ll gg=exgcd(g,c);
	ll s=k/gg;
	y=y*s;x=x*s;
	ll w1=g/gg;
	ll w2=c/gg;
	if(y<0)
	{
		ll sum=(-y)%w1==0?(-y)/w1:(-y)/w1+1;
		y=y+sum*w1;
		x=x-sum*w2;
	}
	ll sum=y/w1;
	y-=sum*w1;
	x+=sum*w2;
	ll cc=y;
	k=x*g;
	gg=exgcd(a,b);
	s=k/gg;
	y=y*s;x=x*s;
	w1=a/gg;w2=b/gg;
	if(x<0)
	{
		ll sum=(-x)%w2==0?(-x)/w2:(-x)/w2+1;
		x=x+sum*w2;
		y=y-sum*w1;
	}
	if(y<0)
	{
		ll sum=(-y)%w1==0?(-y)/w1:(-y)/w1+1;
		x=x-sum*w2;
		y=y+sum*w1;
	}
	printf("%lld %lld %lld
",x,y,cc);
	return 0;
}

虽然正解比暴力长很多 但是打完之后感觉对扩展欧几里得的理解更深了。
以后写的话不会很迷了。

果然做难题是搞定知识的重要途径。

原文地址:https://www.cnblogs.com/chdy/p/12590291.html