QOJ 1963 Squid Game

\(a\le b\le c\)
这显然是可以通过交换得到的。

考虑若 \(a = 1\) 怎么做。
考虑到若把 \(b\) 或者 \(c\)\(a\)\(a\) 就会翻倍。
那就把 \(b\) 拆成二进制,考虑让 \(b\) 变为 \(0\)
从低位到高位,如果 \(b\) 这一位为 \(1\) 就让 \(b\)\(a\),否则 \(c\)\(a\)
那么 \(b\) 最高的一位 \(1\) 也没了后 \(b\) 就为 \(0\) 了。
因为 \(c\ge b\),所以让 \(c\) 消的那一部分是肯定比 \(c\) 小的。
操作次数 \(O(\log V)\)

再考虑 \(a \not = 1\)
那么接下来消就相当于是消 \(\lfloor\frac{b}{a}rfloor\) 的二进制。
那么最后得到的就是 \(b\bmod a\),考虑拿其当作下一轮的 \(a\)
但这样复杂度有点错误,可能 \(b\bmod a = a - 1\),那就会有很多轮。
考虑当 \(b\bmod a \le \frac{a}{2}\) 时用其。
否则 \(a - b\bmod a \le \frac{a}{2}\),就用其作为下一轮的 \(a\)

考虑怎么求出 \(a - b\bmod a\)
那就相当于是消 \(\lfloor\frac{b}{a}\rfloor + 1\),但是特殊的是在最高位的 \(1\) 变为 \(a\)\(b\)

因为下一轮的 \(a'\le \frac{a}{2}\),所以最多只会有 \(O(\log V)\) 轮。
总操作次数 \(O(\log^2 V)\)

#include<bits/stdc++.h>
using i64 = long long;
int main() {
    i64 a, b, c; scanf("%lld%lld%lld", &a, &b, &c);
    int ia = 1, ib = 2, ic = 3;
    std::vector<std::pair<int, int> > ans;
    auto pre = [&]() {
        a > b && (std::swap(a, b), std::swap(ia, ib), 1);
        a > c && (std::swap(a, c), std::swap(ia, ic), 1);
        b > c && (std::swap(b, c), std::swap(ib, ic), 1);
    };
    while (pre(), a) {
        i64 v = b / a;
        if (b % a <= a / 2) {
            for (int i = 0; v; i++, a <<= 1) {
                if (v >> i & 1ll) {
                    v ^= 1ll << i;
                    b -= a, ans.emplace_back(ib, ia);
                } else {
                    c -= a, ans.emplace_back(ic, ia);
                }
            }
        } else {
            v++;
            for (int i = 0; v; i++) {
                if (v >> i & 1ll) {
                    v ^= 1ll << i;
                    if (! v) {
                        a -= b, b <<= 1, ans.emplace_back(ia, ib);
                        break;
                    }
                    b -= a, ans.emplace_back(ib, ia);
                } else {
                    c -= a, ans.emplace_back(ic, ia);
                }
                a <<= 1;
            }
        }
    }
    printf("%zu\n", ans.size());
    for (std::pair<int, int> x : ans) printf("%d %d\n", x.first, x.second);
    return 0;
}
posted @ 2024-01-24 08:15  lhzawa  阅读(22)  评论(0)    收藏  举报