令 \(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;
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);
}
}
}
printf("%zu\n", ans.size());
for (std::pair<int, int> x : ans) printf("%d %d\n", x.first, x.second);
return 0;
}
标签:std,le,frac,bmod,Squid,Game,swap,考虑,QOJ
From: https://www.cnblogs.com/lhzawa/p/17983804