C. Add, Divide and Floor

· · 题解

Description

给定一个长度为 n 的序列 \{a_n\}。每次操作你需要选择一个整数 x 并将所有 a_i 替换为 \lfloor \frac {a_i + x}2 \rfloor。求至少多少次操作后能将所有 a_i 变相同。

若最少次数小于等于 n,输出操作次数和每次操作所选择的 x。否则仅输出操作次数。

## Solution 可以观察到,每次操作后,数字的**相对**大小关系不会发生改变。 例如 $a = \{4, 2, 5\}$,$x = 3$,那么操作后的 $a' = \{3, 2, 4\}$。可以发现 $a_3$ 和 $a'_3$ 分别都是两个序列的最大值,$a_2$ 和 $a'_2$ 都是两个序列的最小值。 那么就启发我们不用同时维护原序列中的所有值,只需要维护序列中的最大值和最小值。当这两个值相等时,就代表序列中所有的数都相同了。 那么问题就被转化成了这样: > 给定两个整数 $a, b$。每次操作你需要选择一个整数 $x$ 并将 $a \gets \lfloor \frac {a + x}2 \rfloor$,$b \gets \lfloor \frac {b + x}2 \rfloor$。求至少多少次操作后 $a = b$。 每次操作我们肯定是希望利用下取整这个优秀性质来让 $a$ 尽量接近 $b$,也就是想让操作后 $a - b$ 尽量小。那么我们可以直接分讨: - $a$ 为偶数,$b$ 为偶数:[$x$ 任意取值](https://www.luogu.com.cn/paste/gx9nzxic); - $a$ 为奇数,$b$ 为奇数:[$x$ 任意取值](https://www.luogu.com.cn/paste/yvohb091); - $a$ 为偶数,$b$ 为奇数:[$x$ 任意一个奇数](https://www.luogu.com.cn/paste/wa8gp7br); - $a$ 为奇数,$b$ 为偶数:[$x$ 任意一个偶数](https://www.luogu.com.cn/paste/uaevgx1b)。 然后就解决了。用 `vector` 记录答案即可。 ## Code ```cpp void solve() { cin >> n; a = 0, b = 2e9; for (int i = 1; i <= n; ++ i ) { cin >> x; a = max(a, x); b = min(b, x); } vector<int> res; while (a != b) { if (a % 2 == 0 && b % 2 == 0) x = rand(); else if (a % 2 == 1 && b % 2 == 1) x = rand(); else if (a % 2 == 0 && b % 2 == 1) x = rand() * 2 + 1; else x = rand() * 2; a = (a + x) / 2; b = (b + x) / 2; res.push_back(x); } cout << res.size() << '\n'; if (res.size() <= n) { for (auto i : res) cout << i << ' '; if (res.size()) puts(""); } return; } ```