• Luogu P1852 BZOJ 2144 [国家集训队]跳跳棋


    qwq

    这题一看就不会,如果不是gg让做我是坚决不会做的

    画图模拟,因为一次只能跳过一个棋子,所以对于一种情况只有三种移动方式:

    1. 中间向左跳
    2. 中间向右跳
    3. 左或右(距中间近的那个)向中间跳

    发现,除了跳到边界,当左右到中间的距离相等的时候就不能再向中间跳了,

    而任意一种情况只要一直重复方式3就能达到这样的平衡状态,也就是说这个状态可以通过方式1、2的组合达到这种情况所有的其他状态。

    把这样的平衡状态当作这种情况的父亲(根节点)。

    那么,首先判断两种情况的根节点是否相同,

    如果相同,说明两种情况在向根节点转移的过程中可能会出现相等的情况。

    最坏的情况,就是一种情况先转移到根节点,再转移到另一种情况。

    如果把转移的过程看做一个树形结构,从某个点向左、右跳是左、右儿子,向中间跳(只有一种可能)是父亲,

    那么从两种情况同时向上找,就类似于一个求lca的过程!

    不过这棵树的左右儿子都是无限的,没法求出所有情况,所以不需要真的求出一棵树。

    只要模拟在树上求LCA的过程即可。

    记录左右两点到中间的距离x,y,若x<y,则左边向中间跳,即左坐标+2x,等同于左、中两点的坐标都+x,

    反之则右、中两点的坐标都-y。

    转移的过程中记录转移的步数可以得到深度。

    首先在找根结点的时候可以得到两种情况到根结点的深度dA,dB,

    然后仿照LCA的过程,把较深的一个向上走|dA-dB|步。

    这时问题来了,既然没有完整的树,也就没法通过倍增的方法向上跳。

    那么就只能一步一步的试了,如果向上一步后两种情况的坐标不同就两步.....

    二分答案枚举步数可以优化这个过程,如果跳mid步后相同,就r=mid,否则l=mid+1。可以看出这个过程和倍增求LCA也是很相似的。

    最后答案即为两个同步跳的+深的节点自己跳的=ans*2+|dA-dB|。

    但是考虑这样一种情况:左、中两点非常近,但右点非常远。这时候左中两点来回相互跳要重复很多次,

    这个y-x-x-x-…一直减到x≥y为止的过程,可以化简为y-kx。

    k=(y-1)/x。为什么呢?当y=x的时候,其实是不能跳的。

    随便带几个数试试:

    坐标为1,3,9,x=2,y=6,跳(6-1)/2=2次,坐标则为5,7,9;

    坐标为1,3,10,x=2,y=7,跳(7-1)/2=3次,坐标则为7,9,10,然后再跳右边的...

    不过这时要注意,如果kx>规定要跳的次数res,那么跳的次数就应该是res而不是kx。

    代码如下

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define MogeKo qwq
    using namespace std;
    const int INF = 2e9+10;
    int dA,dB,dd,ans;
    
    struct node {
        int a,b,c;
        bool operator == (const node &N) const {
            return a==N.a && b==N.b && c==N.c;
        }
        void input() {
            int p[4];
            for(int i = 1; i <= 3; i++)
                scanf("%d",&p[i]);
            sort(p+1,p+4);
            a = p[1],b = p[2],c = p[3];
        }
    } A,B;
    
    node getfa(node t,int res,int &dpth) {
        int cnt;
        dpth = 0;
        while(res) {
            int x = t.b-t.a;
            int y = t.c-t.b;
            if(x == y) return t;
            if(x < y) {
                cnt = min((y-1)/x,res);
                t.a += cnt*x;
                t.b += cnt*x;
            } else {
                cnt = min((x-1)/y,res);
                t.b -= cnt*y;
                t.c -= cnt*y;
            }
            res -= cnt;
            dpth += cnt;
        }
        return t;
    }
    
    int main() {
        A.input(),B.input();
        if(getfa(A,INF,dA) == getfa(B,INF,dB))
            printf("YES
    ");
        else {
            printf("NO
    ");
            return 0;
        }
        if(dA < dB) {
            swap(A,B);
            swap(dA,dB);
        }
        A = getfa(A,dA-dB,dd);
        int l = 0,r = INF;
        while(l < r) {
            int mid = (l+r)>>1;
            if(getfa(A,mid,dd)==getfa(B,mid,dd)) {
                ans = mid;
                r = mid;
            } else l = mid+1;
            
        }
        printf("%d",ans*2+dA-dB);
        return 0;
    }
    View Code
  • 相关阅读:
    如何在DOS中枚举PCI设备
    [Color]深入学习YCbCr色彩模型
    [Imm]Imm API学习笔记——输入法属性
    VBE_INFO(获取VBE信息)
    用VB写高效的图像处理程序 V2.0(2006524)
    ANSI环境下支持多语言输入的单行文本编辑器 V0.01
    分析外星人计算Pi的程序
    位运算模块mBit.bas
    [FileFormat]用VB写的高速GIF、JPEG 编码/解码 程序
    ANTLR笔记3 ANTLRWorks
  • 原文地址:https://www.cnblogs.com/mogeko/p/10622894.html
Copyright © 2020-2023  润新知