一维的数轴上,初始位置在原点,四种移动方式,左移a,右移a,左移b,右移b,问是否可以恰好K步移动到点P,若可以择输出一种可行的方案。
实际上就是解方程
ax+by=P,abs(x)+abs(y)=K
用扩展GCD可以求出一组解,但这组解的绝对值的和不一定是最小的,那么可以通过x+=k*b/gcd,y-=k*a/gcd来尝试收缩出一组绝对值的和最小的解,之后记录res=K-abs(x)-abs(y),如果res是偶数,那么左右来回移动用完剩下的步子就行,奇数的话,讨论a/gcd+b/gcd的奇偶性,如果是奇数,那么可以一次收缩达成上一中情况,否则就是无解了。
另外这题一定注意特判...比如P=0的时候,扩展GCD是搞不出来的,要求一下LCM来得到初始的x,y,之后就一样了。P,K同时等于0的时候直接输出四个0....
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;
typedef long long ll;
ll xx,yy,x,y,tx,ty,px,py;
ll p,k;
bool neg;
ll gcd(ll a,ll b,ll &x,ll &y)
{
if (b==0)
{
x=1;
y=0;
return a;
}
ll d=gcd(b,a%b,x,y);
ll t=x;
x=y;
y=t-a/b*y;
return d;
}
ll lx,ly,rx,ry;
int main()
{
// freopen("in.txt","r",stdin);
cin>>xx>>yy>>p>>k;
ll g=gcd(xx,yy,x,y);
if (p % g!=0)
{
cout<<"NO"<<endl;
return 0;
}
if (p)
{
x=x*p/g;
y=y*p/g;
}
else
{
x=yy/g;
y=-xx/g;
}
px=xx/g;
py=yy/g;
while (abs(x+py)+abs(y-px)<abs(x)+abs(y))
{
x+=py;
y-=px;
}
while (abs(x-py)+abs(y+px)<abs(x)+abs(y))
{
x-=py;
y+=px;
}
if (abs(x)+abs(y)>k)
{
cout<<"NO"<<endl;
return 0;
}
ll res=k-abs(x)-abs(y);
if (res%2==0)
{
if (x>0) rx=abs(x),lx=0;
else rx=0,lx=abs(x);
if (y>0) ry=abs(y),ly=0;
else ry=0,ly=abs(y);
lx+=res/2;
rx+=res/2;
cout<<"YES\n";
cout<<rx<<" "<<lx<<" "<<ry<<" "<<ly<<endl;
return 0;
}
if ( abs(px+py)%2==0)
{
cout<<"NO"<<endl;
return 0;
}
else
{
if (abs(x+py)+abs(y-px)<abs(x-py)+abs(y+px))
{
x+=py;
y-=px;
}
else
{
x-=py;
y+=px;
}
res=k-abs(x)-abs(y);
if (res<0)
{
cout<<"NO"<<endl;
return 0;
}
if (x>0) rx=abs(x),lx=0;
else rx=0,lx=abs(x);
if (y>0) ry=abs(y),ly=0;
else ry=0,ly=abs(y);
lx+=res/2;
rx+=res/2;
cout<<"YES\n";
cout<<rx<<" "<<lx<<" "<<ry<<" "<<ly<<endl;
return 0;
}
return 0;
}