【BZOJ2144】Throw 数论

来源:互联网 发布:统计局数据由哪几部分 编辑:程序博客网 时间:2024/05/22 07:59

题目大意

  给你三个数a,b,c,每次你可以选择一个数s1,再选择一个数s2,把s1变成2s2s1,但要求s3不在s12s2s1之间。

  再给你三个数x,y,z,问你是否能把a,b,c变成x,y,z

  |a|,|b|,|c|,|x|,|y|,|z|109

题解

  首先三个数a,b,c(a<b<c)只能有三种转移:

(a,b,c)(2ab,a,c)(a,c,2cb)(b,2ba,c)     (cb>ba)(a,2bc,b)     (cb<ba)

  可以发现,这些状态构成了一棵树。

  转移可以用辗转相除法加速。

  直接暴力往上跳找LCA即可。

  时间复杂度:O(log(maxamina))

代码

#include<cstdio>#include<cstring>#include<algorithm>#include<cstdlib>#include<ctime>#include<utility>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef pair<int,int> pii;typedef pair<ll,ll> pll;void sort(ll &a,ll &b,ll &c){    if(b<a)        swap(a,b);    if(c<a)        swap(a,c);    if(c<b)        swap(b,c);}void open(const char *s){#ifdef DEBUG    char str[100];    sprintf(str,"%s.in",s);    freopen(str,"r",stdin);    sprintf(str,"%s.out",s);    freopen(str,"w",stdout);#endif}ll gcd(ll a,ll b){    return b?gcd(b,a%b):a;}ll getmid(ll a,ll b,ll c){    while(b-a!=c-b)        if(b-a>c-b)        {            ll j=(b-a)/(c-b);            ll k=c-b;            c-=j*k;            b-=j*k;            if(b==a)            {                b+=k;                c+=k;            }        }        else        {            ll j=(c-b)/(b-a);            ll k=b-a;            a+=j*k;            b+=j*k;            if(b==c)            {                b-=k;                a-=k;            }        }    return b;}pll a1[110];int d1[110];pll a2[110];int d2[110];int cnt1,cnt2;int main(){    open("c");    ll a,b,c,x,y,z;    scanf("%lld%lld%lld%lld%lld%lld",&a,&b,&c,&x,&y,&z);    sort(a,b,c);    sort(x,y,z);    if(gcd(b-a,c-b)!=gcd(y-x,z-y))    {        printf("NO\n");        return 0;    }    if(getmid(a,b,c)!=getmid(x,y,z))    {        printf("NO\n");        return 0;    }    printf("YES\n");    pll s1(b-a,c-b);    pll s2(y-x,z-y);    cnt1=cnt2=0;    d1[0]=d2[0]=0;    while(s1.first!=s1.second)    {        a1[++cnt1]=s1;        if(s1.first>s1.second)        {            d1[cnt1]=s1.first/s1.second;            s1.first%=s1.second;            if(!s1.first)            {                s1.first=s1.second;                d1[cnt1]--;            }        }        else        {            d1[cnt1]=s1.second/s1.first;            s1.second%=s1.first;            if(!s1.second)            {                s1.second=s1.first;                d1[cnt1]--;            }        }    }    a1[++cnt1]=s1;    d1[cnt1]=0;    reverse(a1+1,a1+cnt1+1);    reverse(d1+1,d1+cnt1+1);    while(s2.first!=s2.second)    {        a2[++cnt2]=s2;        if(s2.first>s2.second)        {            d2[cnt2]=s2.first/s2.second;            s2.first%=s2.second;            if(!s2.first)            {                s2.first=s2.second;                d2[cnt2]--;            }        }        else        {            d2[cnt2]=s2.second/s2.first;            s2.second%=s2.first;            if(!s2.second)            {                s2.second=s2.first;                d2[cnt2]--;            }        }    }    a2[++cnt2]=s2;    d2[cnt2]=0;    reverse(a2+1,a2+cnt2+1);    reverse(d2+1,d2+cnt2+1);    ll ans=0;    int i,j;    for(i=1;i<=cnt1;i++)        d1[i]+=d1[i-1];    for(i=1;i<=cnt2;i++)        d2[i]+=d2[i-1];    i=cnt1,j=cnt2;    while(a1[i-1]!=a2[j-1])        if(d1[i-1]>d2[j-1])        {            ans+=d1[i]-d1[i-1];            i--;        }        else        {            ans+=d2[j]-d2[j-1];            j--;        }    if(a1[i].first==a2[j].first||a1[i].second==a2[j].second)    {        if(d1[i]>d2[j])            ans+=d1[i]-d2[j];        else            ans+=d2[j]-d1[i];    }    else        ans+=d1[i]-d1[i-1]+d2[j]-d2[j-1];    printf("%lld\n",ans);    return 0;}
原创粉丝点击