zoukankan      html  css  js  c++  java
  • P1852 [国家集训队]跳跳棋

    P1852 [国家集训队]跳跳棋

    题目描述

    跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。

    我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。(棋子是没有区别的)

    跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。

    写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。

    输入输出格式

    输入格式:

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

    第二行包含三个整数,表示目标位置x y z。(互不相同)

    输出格式:

    如果无解,输出一行NO。

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

    输入输出样例

    输入样例#1: 复制
    1 2 3
    0 3 5
    输出样例#1: 复制
    YES
    2

    说明

    20% 输入整数的绝对值均不超过10

    40% 输入整数的绝对值均不超过10000

    100% 绝对值不超过10^9

    题解:一道好题,考思维和代码

    抽象的树型结构,向中间跳就是指向父亲节点,向两边跳就是指向儿子结点,判断两个状态是否合法,先判断是否在同一颗树中,倍增跳到同一深度后,在二分跳的步数直到相遇。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int M = 1e5 + 5;
    #define For(i, b, c) for(int i = b; i <= c; i++)
    #define ll long long
    int t[4], s[4], ori[4], tgr[4]; 
    ll go(int a, int b, int c){
        if(c - b == b - a){
            t[1] = a, t[2] = b, t[3] = c;
            return 0;
        }
        if(c - b > b - a){
            int dx = b - a;
            int cx = (c - b)/dx, res = (c - b)%dx;
            if(!res) cx--, res += dx;
            return cx + go(c - dx - res, c - res, c);
        }
        else {
            int dx = c - b;
            int cx = (b - a)/dx, res = (b - a)%dx;
            if(!res) cx--, res += dx;
            return cx + go(a, a + res, a + res + dx);
        }
    }
    
    void up(int a, int b, int c, ll lim){
        if(!lim || b - a == c - b){
            t[1] = a, t[2] = b, t[3] = c;
            return ;    
        }
        if(c - b > b - a){
            int dx = b - a;
            int cx = (c - b)/dx, res = (c - b)%dx;
            if(!res) cx--, res += dx;
            if(cx > lim){
                up(a + dx*lim, a + dx*(lim+1), c, 0);
            }
            else up(c - dx - res, c - res, c, lim - cx);
        }
        else {
            int dx = c - b;
            int cx = (b - a)/dx, res = (b - a)%dx;
            if(!res) cx--, res += dx;
            if(cx > lim){
                up(a, c - dx*(lim+1), c - dx*lim, 0);
            }
            else up(a, a + res, a + res + dx, lim - cx);
        }
        
        
    }
    
    bool check(ll k){
        up(ori[1], ori[2], ori[3], k);
        For(i, 1, 3) s[i] = t[i];
        up(tgr[1], tgr[2], tgr[3], k);
        For(i, 1, 3) if(s[i] != t[i])return 0;
        return 1;
    }
    
    int main(){
        scanf("%d%d%d%d%d%d",&ori[1], &ori[2], &ori[3], &tgr[1], &tgr[2], &tgr[3]);
        sort(ori+1, ori+4); sort(tgr+1, tgr+4);
        ll stp1 = go(ori[1], ori[2], ori[3]);
        For(i, 1, 3) s[i] = t[i];
        ll stp2 = go(tgr[1], tgr[2], tgr[3]);
        For(i, 1, 3) 
            if(t[i] != s[i]){
                puts("NO");return 0;
            }
        ll tmp = 0;
        if(stp1 > stp2){
            tmp = stp1 - stp2;
            up(ori[1], ori[2], ori[3], tmp);
            For(i, 1, 3)ori[i] = t[i];
        }
        else if(stp1 < stp2){
            tmp = stp2 - stp1;
            up(tgr[1], tgr[2], tgr[3], tmp);
            For(i, 1, 3)tgr[i] = t[i];
        }
        ll lf = 0, rg = min(stp1, stp2), ans = -1;
        while(lf <= rg){
            ll mid = (lf + rg) >> 1;
            if(check(mid))rg = mid - 1, ans = mid;
            else lf = mid + 1;
        }
        printf("YES
    %lld
    ",tmp + ans*2);
    }
    View Code
  • 相关阅读:
    XtraFinder在OSX10.11的使用
    meterpreter > migrate 1548
    meterpreter > ps
    meterpreter > sysinfo
    meterpreter > screenshot
    ubuntu
    一次真是渗透
    nmap -sT -A --script=smb-check-vulns -PO 172.16.21.170
    use scanner/smb/smb_version
    scanner/portscan/syn
  • 原文地址:https://www.cnblogs.com/EdSheeran/p/9904803.html
Copyright © 2011-2022 走看看