• p2024


      这是一道很有意思的题.不要被国家集训队的标签吓到,我们仔细思考跳的时候的性质.

      玩过跳棋的应该都可以接受题意. 可以把每次'跳'分为两种:一种是中间的棋子以两边的棋子为'中轴棋子'跳,显然想向哪跳就向哪跳,只会跳过一个棋子.一种是两边的棋子向中间跳.这种可能不能跳:左中和中右间的距离相同,无法再跳.能跳也只会有一种情况:距离小一点的向距离更大的那两个棋子间跳.

      画一下图应该比较容易理解.

      比如样例1,2,3就只能向'外'跳了,1向2,3跳或 3向1,2跳就是不允许的.

      比如样例0,3,5既能向'外'跳,5也能向'里'跳,0就不能向右跳.

      也就是说,我们把所有的状态看做一个森林,根节点们一定都是x,y,z距离相同的状态.其他的所有状态存在且一定只存在与一棵树上面.

      我们可以用这样的方法向上跳到一个状态的根节点上去:

      每次算出xy,yz间的距离.令距离小的向距离大的点跳.直到距离相同.

      

      这样好像挺慢的对吧,如果y=x+1,我们需要跳z-y次.这个时候又发现好像可以连着跳...

      例如如果u<v,我们可以连着跳上个v/u次.反之亦然.

      

      这样就快了很多.从最坏2e9到最坏小于log(2e9).为什么会这样呢?不妨设u<v,跳完后总距离就会小于u,而u正是小于总距离的一半的.也就是说,每次跳k次后都会减少一半多.

      基于这个while,我们还可以询问第k个祖先是谁,距离根节点的距离.于是仿照树上倍增LCA,本题就可以愉快的A掉了.我们先找到根节点,判断是否一样.然后调整到'深度'一样的,判断是否一样.然后向上调整.

      

    using namespace std;
    struct node 
    {
        long long x,y,z;
        long long deep;
        friend bool operator ==(node a,node b)
        {
            return a.x==b.x&&a.y==b.y&&a.z==b.z;
        }
        friend bool operator !=(node a,node b)
        {
            return !(a==b);
        }
    }a,b;
    
    void tiao(node &c)
    {
        if(c.x>c.y)
            swap(c.x,c.y);
        if(c.x>c.z)
            swap(c.x,c.z);
        if(c.y>c.z)
            swap(c.y,c.z);
    }
    node getfa(node now,long long s)
    {
        long long u=now.y-now.x,v=now.z-now.y;
        for(;s&&u!=v;)
        {
            if(u<v)
            {
                long long k=min((v-1)/u,s);
                now.x+=k*u;now.y+=k*u;s-=k;
            }
            else
            {
                long long k=min((u-1)/v,s);
                now.y-=k*v,now.z-=k*v,s-=k;
            }
            u=now.y-now.x,v=now.z-now.y;
        }
        return now;
    }
    long long getdeep(node now)
    {
        long long u=now.y-now.x,v=now.z-now.y,sum=0,k;
        for(;u!=v;)
        {
            if(u<v)
            {
                k=(v-1)/u;
                now.x+=k*u;now.y+=k*u;
            }
            else
            {
                k=(u-1)/v;
                now.y-=k*v,now.z-=k*v;
            }
            u=now.y-now.x,v=now.z-now.y;
            sum+=k;
        }
        return sum;
    }
    void write(node a)
    {
        cout<<a.x<<' '<<a.y<<' '<<a.z<<endl;
    }
    int main()
    {
        cin>>a.x>>a.y>>a.z>>b.x>>b.y>>b.z;
        tiao(a);tiao(b);
        if(getfa(a,2999999998)==getfa(b,2999999998))
        {
            cout<<"YES"<<' ';
        }
        else 
        {
            cout<<"NO";
            return 0;
        }
        long long deep1=getdeep(a),deep2=getdeep(b);
        if(deep1>deep2)
        {
            a=getfa(a,deep1-deep2);
        }
        if(deep1<deep2)
        {
            b=getfa(b,deep2-deep1);
        }
        if(a==b)
        {
            cout<<abs(deep1-deep2);
            return 0;
        }
        long long sum=0;
        for(long long i=30;i>=0;i--)
        {
            node tx=getfa(a,1<<i),ty=getfa(b,1<<i);
            if(tx!=ty)
            {    
                a=tx,b=ty;
                sum+=(1<<i);
            }
        }
        cout<<abs(deep1-deep2)+2*(sum+1);
        return 0;
    }
    View Code

      

  • 相关阅读:
    gc的real时间比user时间长
    java 反射: 当Timestamp类型的属性值为null时,设置默认值
    多线程注意点
    多线程socket编程示例
    一个类有两个方法,其中一个是同步的,另一个是非同步的; 现在又两个线程A和B,请问:当线程A访问此类的同步方法时,线程B是否能访问此类的非同步方法?
    含有Date和Timestamp的Java和Json互相转化
    java bean、List、数组、map和Json的相互转化
    并发抢购
    SQL 性能调优日常积累【转】
    String和包装类IntegerDoubleLongFloatCharacter 都是final类型
  • 原文地址:https://www.cnblogs.com/qywyt/p/10487219.html
Copyright © 2020-2023  润新知