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;
}
posted @ 2020-09-22 16:27  刘子闻  阅读(89)  评论(0编辑  收藏  举报