20200922day18 刷题记录
1 跳跳棋
题面
跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。我们用跳跳棋来做一个简单的游戏:棋盘上有三颗棋子,分别在 \(a,b,c\) 这三个位置。我们要通过最少的跳动把他们的位置移动成 \(x,y,z\)
(注意:棋子是没有区别的)。
跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过一颗棋子。
写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。
样例输入
1 2 3
0 3 5
样例输出
YES
2
题解
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;
int read() {
int a = 0, x = 1;
char ch = getchar();
while (ch > '9' || ch < '0') {
if (ch == '-')
x = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
a = a * 10 + ch - '0';
ch = getchar();
}
return a * x;
}
struct node {
int a[4];
friend bool operator!=(node a, node b) {
for (int i = 1; i <= 3; i++)
if (a.a[i] != b.a[i])
return true;
return false;
}
friend bool operator==(node a, node b) { return !(a != b); }
void print() { printf("%lld %lld %lld\n", a[1], a[2], a[3]); }
} A, B;
const int inf = 1e18;
node r1, r2;
int temp = 0, dep1, dep2;
node find(node S, int k) {
int z1 = S.a[2] - S.a[1], z2 = S.a[3] - S.a[2], tmp;
if (z1 > z2) {
tmp = min((z1 - 1) / z2, k);
z1 -= tmp * z2;
temp += tmp;
k -= tmp;
S.a[2] -= tmp * z2, S.a[3] -= tmp * z2;
} else if (z1 < z2) {
tmp = min((z2 - 1) / z1, k);
z2 -= tmp * z2;
k -= tmp;
temp += tmp;
S.a[1] += tmp * z1, S.a[2] += tmp * z1;
}
if (z1 == z2)
return S;
if (k)
return find(S, k);
return S;
}
signed main() {
for (int i = 1; i <= 3; i++) A.a[i] = read();
for (int i = 1; i <= 3; i++) B.a[i] = read();
sort(A.a + 1, A.a + 4);
sort(B.a + 1, B.a + 4);
r1 = find(A, inf);
dep1 = temp, temp = 0;
r2 = find(B, inf);
dep2 = temp, temp = 0;
if (r1 != r2) {
printf("NO");
return 0;
}
if (dep1 < dep2) {
swap(dep1, dep2);
swap(A, B);
}
A = find(A, dep1 - dep2);
int l = 0, r = dep2, mid;
while (l != r) {
mid = l + r >> 1;
if (find(A, mid) == find(B, mid))
r = mid;
else
l = mid + 1;
}
printf("YES\n%lld", l * 2 + (dep1 - dep2));
return 0;
}
要做就做南波万