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

    题目大意:

    给定一条数轴,上面有三个棋子,分别在(a) , (b), (c) 三个位置。

    棋子只能在整点上,每个点只能最多只能有一个棋子。

    现在,我们要把棋子用最少的步数跳到 (x), (y), (z) (棋子是没有区别的)。

    跳动的规则很简单,任选一个棋子,选择另一个棋子为中轴棋子翻一个跟斗,跳了之后两棋子距离不变。一次只允许跳过一个棋子。

    判断是否可以完成任务,如果可以,输出最少需要跳动的次数。

    输入的所有值的绝对值不超过(10^9)

    样例:

    1 2 3
    0 3 5
    
    YES
    2
    

    思路:

    %%%%%%%%%%

    神题!神题!神题!

    题目很简洁,正解很神奇!!!!

    首先,假设一个递增三元组 ((x, y, z)) ,来看一下这个三元组一共有多少种跳法。

    (y) 向左跳过 (x) ,形成 ((2 imes x - y, x, z))

    (y) 向右跳过 (x), 形成 ((x,z,2 imes z - y))

    还有 (x)(z) 向内跳,但是因为只能越过一个棋子,所以最多只有一种跳法。

    (d_1 = y - x, d_2 = z - y)

    (d_1 < d_2), ((y, y + d_1, z))

    (d_1 > d_2), ((x, z - d2, z))

    (d_1 = d_2), 则该状态不可向内跳。

    发现没有,若向内跳,必定只会有一种方法,且一定有边界。从边界转移到一个状态有且仅会有一种方法,其次一个状态往其他状态转移时有两种方法,且边界在不断扩大,所以不会有环。

    上述描述是不是很像一颗二叉树???

    边界就是根,两种向外跳的方法就是两个儿子,向内跳的方法就是父亲。

    所以判断有没有解,就可以直接判断两颗树的根是否相同。

    其实能想到现在,正解已经很近了,现在就是如何优化这个跳的过程。

    回到上面向内跳的过程:

    ((y, y +d_1, z))((x,z - d_2, y))

    若我往一边跳,那么这一边的 (d) 值是不变的。所以不用一次跳一下,一次不停地往那边跳,知道大于等于另一边的 (d)值。这个就是 ((d_1, d_2) Rightarrow (d_2 \% d_1, d_1)) ,这不就是一个(gcd) 的复杂度吗。

    其次,统计答案就非常简单了,二分+LCA计算就好了。

    代码:

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define REP(i, a, n) for (register int i = a, _n = n; i <= _n; ++i)
    #define DREP(i, a, n) for (register int i = a, _n = n; i >= _n; --i)
    #define FOR(i, a, n) for (register int i = a, _n = n; i < _n; ++i)
    #define EREP(i, a) for (register int i = first[a]; i; i = edge[i].nxt)
    #define debug(x) cout << #x << " = " << x << endl
    
    char IO;
    inline int rd () {
    	int res = 0;
    	while ((IO = getchar()) && (IO < '0' || IO > '9'));
    	while (IO >= '0' && IO <= '9') res = (res << 1) + (res << 3) + (IO ^ 48), IO = getchar();
    	return res;
    }
    
    void jump (int& a, int& b, int& c, int& len) {
    	int d1 = b - a, d2 = c - b;
    	while (d1 != d2) {
    		if (d1 < d2) {
    			len += (d2 - 1) / d1;
    			d2 = (d2 - 1) % d1 + 1;
    			a = c - d1 - d2;
    			b = c - d2;
    		} else {
    			len += (d1 - 1) / d2;
    			d1 = (d1 - 1) % d2 + 1;
    			b = a + d1;
    			c = a + d1 + d2;
    		}
    		d1 = b - a, d2 = c - b;
    	}
    }
    void Up (int& ta, int& tb, int& tc, int len) {
    	int a = ta, b = tb, c = tc;
    	while (len) {
    		int d1 = b - a, d2 = c - b;
    		if (d1 < d2) {
    			int tim = min(d2 / d1, len);
    			len -= tim;
    			a = b + (tim - 1) * d1;
    			b = b + tim * d1;
    		} else {
    			int tim = min(d1 / d2, len);
    			len -= tim;
    			c = b - (tim - 1) * d2;
    			b = b - tim * d2;
    		}
    	}
    	ta = a, tb = b, tc = c;
    }
    
    int a, b, c, l1, ta, tb, tc;
    int x, y, z, l2, tx, ty, tz;
    
    int main () {
    	scanf ("%d%d%d", &a, &b, &c);
    	scanf ("%d%d%d", &x, &y, &z);
    	if (a > b) swap(a, b);
    	if (b > c) swap(b, c);
    	if (a > b) swap(a, b);
    	if (x > y) swap(x, y);
    	if (y > z) swap(y, z);
    	if (x > y) swap(x, y);
    	ta = a, tb = b, tc = c;
    	tx = x, ty = y, tz = z;
    	jump(ta, tb, tc, l1);
    	jump(tx, ty, tz, l2);
    
    	if (ta != tx || tb != ty || tc != tz) {
    		puts("NO");
    		return 0;
    	}
    
    	if (l1 > l2) {
    		Up(a, b, c, l1 - l2);
    	} else if (l1 < l2) {
    		Up(x, y, z, l2 - l1);
    	}
    
    	if (a == x && b == y && c == z) return !printf ("YES
    %d
    ", abs(l1 - l2));
    
    	int l = 1, r = min(l1, l2), res;
    
        while (l <= r) {
        	int mid = l + r >> 1;
        	ta = a, tb = b, tc = c;
        	tx = x, ty = y, tz = z;
        	Up(ta, tb, tc, mid);
        	Up(tx, ty, tz, mid);
        	if (ta == tx && tb == ty && tc == tz) {
        		res = mid;
        		r = mid - 1;
        	} else {
        		l = mid + 1;
        	}
        }
    
    	printf ("YES
    %d
    ", res * 2 + abs(l1 - l2));
    
    	return 0;
    }
    

    总结:

    首先这题的确非常好,没有过多的算法,建模过程很有意思,也能顺水推舟的写下来。以后做题时可以手玩一下样例,发现一些性质,而不是瞪着题目发呆。

  • 相关阅读:
    Git常用操作命令
    百度地图集成--二
    百度地图的集成--超详细
    iOS开发系列--地图与定位
    整理了一份React-Native学习指南(转)
    iOS高级编程之JSON,XML数据解析
    iOS开发基础
    C#001
    C#00
    英语学习tips
  • 原文地址:https://www.cnblogs.com/ZPAYAUR/p/11178555.html
Copyright © 2011-2022 走看看