• [luogu]P1852跳跳棋


    题目重点是每次不能跳过两个棋子

    即对于每一个棋子的状态(a,b,c) (a<b<c)

    最多有两种移动的方式

    1.中间往两边跳 (a,b,c)-->(2b-a,a,c)或(a,c,2b-c)

    2.a或c往中间跳 当然要满足不跳过两个棋子

    b-a<c-b a可以跳过b (a,b,c)-->(b,2b-a,c)

    c-b<b-a c可以跳过b (a,b,c)-->(a,2b-c,b)

    当然当c-b=b-a时就不能再往中间跳了

    此时可以想到对于一个状态(a,b,c)如果一直往中间跳 最终的状态一定是一定的

    于是可以把这个最终的状态看做是根节点 中间向左向右跳的状态分别是左右节点

    这样就是一棵二叉树了,而询问两个状态能否相互跳到就是树上距离了

    于是回顾lca求树上距离的过程,我们首先要确定一个状态的k层祖先的状态是什么

    如果暴力跳的话就会超时,所以我们想一种特殊的情况

    (1,100000000,100000001) 显然暴力跳会一直跳1的长度是不行的

    但我们看这时b-a很大但c-b很小就意味着接下来会很多次都是c往b跳

    能跳几次呢?因为棋子实际上没有区别 假如c跳过b 那么实际上就是c和b一起向左平移了c-b的距离

    所以c往b跳的次数就是(b-a)/(c-b)

    这样对于本题就可以达到取模gcd的速度快速求出一个状态的k层祖先状态

    这样用lca的手法先让两点到达同一高度,再二分一个距离k,如果两种状态的k层祖先一直 则将k缩小,反之增大求出他们的最近公共祖先

    #include<bits/stdc++.h>
    using namespace std;
    int ans,a,b,c,x,y,z,x1,yy1,z1,a1,b1,c1,t1,t2;
    int read()
    {
        int f=1,x=0;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(x=x*10+ch-48,ch=getchar(),ch>='0'&&ch<='9');
        return x*f;
    }
    void SWAP(int &a,int &b,int &c){if(a>b){swap(a,b);if(a>c)swap(a,c);}if(b>c)swap(b,c);}
    void back(int &a,int &b,int &c,int k)//将状态a,b,c回到k步前的状态 即它的k层祖先 
    {
        int A=b-a,B=c-b;
        if(A<B)
        {
            int t=B/A;if(B%A==0)t--;
            if(t>=k){a=a+k*A;b=b+k*A;}
            else {a=a+t*A;b=b+t*A;back(a,b,c,k-t);}
        }else
        {
            int t=A/B;if(A%B==0)t--;
            if(t>=k){c=c-k*B;b=b-k*B;}
            else {c=c-t*B;b=b-t*B;back(a,b,c,k-t);}
        }
    }
    int getfa(int &a,int &b,int &c)//寻找状态a,b,c的根节点 
    {
        int A=b-a,B=c-b;
        if(A==B)return 0;
        if(A<B)
        {
            int t=B/A;if(B%A==0)t--;
            a=a+t*A;b=b+t*A;
            return t+getfa(a,b,c);
        }else
        {
            int t=A/B;if(A%B==0)t--;
            c=c-t*B;b=b-t*B;
            return t+getfa(a,b,c);
        }
    }
    int comp(int a,int b,int c,int x,int y,int z){if(a==x&&b==y&&c==z)return 1;else return 0;}
    int main()
    {
        a=read();b=read();c=read();
        x=read();y=read();z=read();
        SWAP(a,b,c);SWAP(x,y,z);
        x1=x;yy1=y;z1=z;a1=a;b1=b;c1=c;
        t1=getfa(x1,yy1,z1);t2=getfa(a1,b1,c1);
        if(!comp(x1,yy1,z1,a1,b1,c1)){puts("NO");return 0;}
        if(t1<t2) back(a,b,c,t2-t1);else back(x,y,z,t1-t2);
        int l=0,r=min(t1,t2);
        while(l<=r)
        {
            int mid=(l+r)>>1;
            x1=x;yy1=y;z1=z;a1=a;b1=b;c1=c;
            back(x1,yy1,z1,mid);back(a1,b1,c1,mid);
            if(comp(a1,b1,c1,x1,yy1,z1)) ans=mid,r=mid-1;else l=mid+1;
        }
        puts("YES");
        printf("%d",2*ans+max(t2,t1)-min(t2,t1));
        return 0;
    }
    /*
    (a,b,c)
    
    if b-a<c-b --> (b,2b-a,c)
    if c-b<b-a --> (a,2b-c,b)
    
    
    */
    
  • 相关阅读:
    py 5.11
    py 5.10
    py 5.9
    py 5.8
    python 5.7
    python 5.4
    python 5.3
    python 5.2
    python 4.28
    python 4.27
  • 原文地址:https://www.cnblogs.com/DavidJing/p/10354511.html
Copyright © 2020-2023  润新知