zoj3593 扩展欧几里德

来源:互联网 发布:淘宝给老客户发优惠券 编辑:程序博客网 时间:2024/06/06 05:02

副标题:以为可以脱非扩欧,奈何败于智商不足

题目分析

首先这个c=a+b,所以我们可以暂时只考虑ab,那么假设L=abs(BA),则就是要解这个方程:ax+by=c,这个是扩欧的事情,无解的判断与扩欧一样,不多叙述。
但是解出了一个解之后是不够的,还要求最优解。
容易意会得到,如果a=a/gcd(a,b),b=b/gcd(a,b),那么通过扩欧可以得到一个特解x0y0,然后通解可以表示为x=x0+aty=y0bt
可以在坐标系上画出两条直线l1,l2(注意上式中的x不同于坐标系的x轴,x轴准确的说应该是t轴!),并且斜率是一正一负(a,b同正,题目已说)
所以呢,取一个t,如果xy异号,答案就是你画一条平行于y轴的直线,它和l1,l2的交点间的距离。如果同号就是在这两条直线上横坐标为t的离x轴远的那个点离x轴的距离,那么意会可得,l1,l2交点处取到最优解,由于交点处的t不一定是整数,所以我们要做一些处理(见代码)

代码

#include<cstdio>#include<iostream>#include<cmath>#include<climits>using namespace std;#define ll long longll read(){    ll q=0,w=1;char ch=' ';    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();    if(ch=='-')w=-1,ch=getchar();    while(ch>='0'&&ch<='9')q=(ll)q*10+(ll)(ch-'0'),ch=getchar();    return q*w;}ll exgcd(ll a,ll b,ll &x,ll &y){    if(!b){x=1;y=0;return a;}    ll d=exgcd(b,a%b,x,y),tmp;    tmp=x;x=y;y=tmp-(a/b)*y;    return d;}ll s,t,a,b,T,mi;int main(){    ll x,y,d,L,i;    T=read();    while(T--){        s=read();t=read();a=read();b=read();        d=exgcd(a,b,x,y);L=abs(t-s);        if(L%d){printf("-1\n");continue;}        ll ans=LLONG_MAX,kl;        x=x*(L/d);y=y*(L/d);a/=d;b/=d;        mi=(y-x)/(a+b);//交点        for(i=mi-1;i<=mi+1;i++){//讨论整点            if(fabs(x+b*i)+fabs(y-a*i)==fabs(x+b*i+y-a*i))                kl=max(x+b*i,y-a*i);            else kl=fabs(x-y+(a+b)*i);//是加号QAQ            ans=min(ans,kl);        }        printf("%lld\n",ans);    }    return 0;}