zoukankan      html  css  js  c++  java
  • bzoj 2144: 跳跳棋——倍增/二分

    Description

    跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。(棋子是没有区别的)跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。  写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。

    Input

    第一行包含三个整数,表示当前棋子的位置a b c。(互不相同)第二行包含三个整数,表示目标位置x y z。(互不相同)

    Output

    如果无解,输出一行NO。如果可以到达,第一行输出YES,第二行输出最少步数。

    Sample Input

    1 2 3
    0 3 5

    Sample Output

    YES
    2

    【范围】
    100% 绝对值不超过10^9
    ——————————————————————————————————
    这道题我们发现如果从中间往两边跳的话 有两种状态 而从两边往中间跳的话只有一种状态
    刚好非常符合树形状 那么我么把一个点向外跳的状态在状态树上表示为这个点的儿子
    向内表示为父亲 那么如果这两个初始状态在树上有lca就有答案 这个我们可以先像倍增求lca一样
    先将两个状态跳到同一深度然后再二分深度(答案)及可以辣
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using std::swap;
    using std::min;
    const int inf=0x3f3f3f3f;
    int read(){
        int ans=0,f=1,c=getchar();
        while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
        return ans*f;
    }
    int len,lena,lenb,h;
    struct pos{int x,y,z;}a,b,yy,ly;
    pos up(pos s,int T){
        for(len=0;T;len+=h){
            int l=s.y-s.x,r=s.z-s.y;
            if(l==r) return s;
            if(l<r) h=min(T,(r-1)/l),s.x+=h*l,s.y+=h*l;
            else h=min(T,(l-1)/r),s.y-=h*r,s.z-=h*r;
            T-=h;
        }
        return s;
    }
    void sort(pos &s){
        if(s.x>s.z) swap(s.x,s.z);
        if(s.x>s.y) swap(s.x,s.y);
        if(s.y>s.z) swap(s.y,s.z);
    }
    int main(){
        a.x=read(); a.y=read(); a.z=read(); sort(a);
        b.x=read(); b.y=read(); b.z=read(); sort(b);
        yy=up(a,inf); lena=len;
        ly=up(b,inf); lenb=len;
        if(yy.x!=ly.x||yy.y!=ly.y||yy.z!=ly.z) return puts("NO"),0;
        puts("YES");
        if(lena<lenb) swap(a,b),swap(lena,lenb);
        a=up(a,lena-lenb);
        int l=0,r=lenb;
        while(l<r){
            int mid=(l+r)>>1;
            yy=up(a,mid); ly=up(b,mid);
            if(yy.x==ly.x&&yy.y==ly.y&&yy.z==ly.z) r=mid;
            else l=mid+1;
        }
        printf("%d",(l<<1)+lena-lenb);
        return 0;
    }
    View Code
  • 相关阅读:
    [斜率优化][DP]luogu P3648 序列分割
    [状压DP]luogu P1879 玉米田
    [最短路][期望DP]luogu P1850 换教室
    [DP]JZOJ 3046 游戏
    [组合数学]JZOJ 3013 填充棋盘
    [贪心]JZOJ 3012 购买
    [最大流][二分]JZOJ 1259 牛棚
    [数学][构造]JZOJ 3317 管道
    Cookie和Session
    XSS和CSRF的理解
  • 原文地址:https://www.cnblogs.com/lyzuikeai/p/7636496.html
Copyright © 2011-2022 走看看