BZOJ2144 跳跳棋

题目蓝链

Solution

这道题有一个很巧妙的性质,那就是所有的状态都是由三个两两差距相等的点转移过来的。所以我们一开始只需要把两边的点往中间转移,如果最后转移到一个状态,那么就有解

现在我们考虑怎么快速转移。我们设当前的两两差距为\((a, b)\),我们有两种转移方法,\((a - b, b)\)\((a, b - a)\)。其实这个转移等价于\((a \% b, b)\)\((a, b \% a)\),每次取模会至少把数字减少一半,所以这个过程的复杂度是\(log\)级别的。

现在我们可以利用这个方法快速求出任意一个状态往中间转移\(k\)次后的状态,然后我们就可以利用一个类似于在树上找LCA的方法求出他们最近的公共的状态就可以了(其实感觉是二分),答案就是起始状态与目标状态到这个公共状态的距离和

Code

#include <bits/stdc++.h>

using namespace std;

#define squ(x) ((LL)(x) * (x))
#define debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef pair<int, int> pii;

inline int read() {
	int sum = 0, fg = 1; char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') fg = -1;
	for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
	return fg * sum;
}

const int inf = 1e9;

struct node {
	int x, y, z;
	bool operator == (const node &t) { return (x == t.x) & (y == t.y) & (z == t.z); }
	bool operator != (const node &t) { return (x != t.x) | (y != t.y) | (z != t.z); }
	void input() {
		static int tmp[3];
		for (int i = 0; i < 3; i++) tmp[i] = read();
		sort(tmp, tmp + 3);
		x = tmp[0], y = tmp[1], z = tmp[2];
	}
}a, b;

node get_fa(node now, int res, int &hk) {
	int k;
	for (hk = 0; res; hk += k) {
		int x = now.y - now.x, y = now.z - now.y;
		if (x == y) break;
		if (x < y) {
			k = min((y - 1) / x, res);
			now.x += k * x; now.y += k * x;
			res -= k;
		}else {
			k = min((x - 1) / y, res);
			now.y -= k * y; now.z -= k * y;
			res -= k;
		}
	}
	return now;
}

int main() {
#ifdef xunzhen
	freopen("jump.in", "r", stdin);
	freopen("jump.out", "w", stdout);
#endif

	a.input(), b.input();
	int da, db;
	if (get_fa(a, inf, da) != get_fa(b, inf, db)) {
		printf("NO\n");
		return 0;
	}
	if (da < db) swap(da, db), swap(a, b);

	int hk;
	a = get_fa(a, da - db, hk);

	int l = 0, r = inf;
	while (l <= r) {
		int mid = (l + r) >> 1;
		if (get_fa(a, mid, hk) == get_fa(b, mid, hk)) r = mid - 1;
		else l = mid + 1;
	}
	r++;
	printf("YES\n%d\n", (r << 1) + (da - db));

	return 0;
}

Summary

这真的是一道神题,感觉需要一定的做题经验才能发现这个题的神奇性质

以后看到这种多次相同的两个数相减,都一定要往取模的方向去想

posted @ 2018-09-20 21:11  xunzhen  阅读(154)  评论(0编辑  收藏  举报