一、题目
1、题目描述
2、输入输出
2.1输入
2.2输出
3、原题链接
1901C - Add, Divide and Floor
二、解题报告
1、思路分析
我们假设将原数组排序,那么每次操作不会改变数组单调性
当 最大值 调整等于 最小值时 所有数都相等,因为单调性不变,比最小值大的数过程中都始终 >= 最小值
我们考虑每次操作的影响,设最大值为ma,最小值为mi
假如 ma 和 mi 都是 偶数
那么 (ma + x) / 2 - (mi + x) / 2 = (ma - mi) / 2
也就是说,我们的差值变为原来一半
我们可以枚举ma mi 奇偶的4种情况,我们发现我们通过调整 x 的取值可以使得每次差值都减少为原来一半,由于操作限制每次除2,故不会有比这更优的操作了
更具体地,当最小值为奇数,我们取x = 1,偶数取x = 0
具体为什么通过举具体例子可得,当然也可以更一般性地推导,这里略
2、复杂度
时间复杂度: O(N + logU)空间复杂度:O(1)
3、代码详解
#include <bits/stdc++.h>
#define sc scanf
using i64 = long long;
using PII = std::pair<int, int>;
constexpr int inf32 = 1e9 + 7;
constexpr i64 inf64 = 1e18 + 7;
constexpr int P = 998244353;
// #define DEBUG
void solve()
{
int n;
std::cin >> n;
int mi = inf32, ma = -inf32;
for (int i = 0, a; i < n; ++ i) {
std::cin >> a;
mi = std::min(mi, a);
ma = std::max(ma, a);
}
if (mi == ma) {
std::cout << 0 << '\n';
return;
}
std::vector<int> ans;
while (mi != ma) {
ans.push_back(mi & 1);
mi = (mi + ans.back()) / 2;
ma = (ma + ans.back()) / 2;
}
if (ans.size() <= n) {
std::cout << ans.size() << '\n';
for (int i = 0; i < ans.size(); ++ i)
std::cout << ans[i] << " \n"[i + 1 == ans.size()];
}
else
std::cout << ans.size() << '\n';
}
int main()
{
#ifdef DEBUG
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(false), std::cin.tie(nullptr), std::cout.tie(nullptr);
int _ = 1;
std::cin >> _;
while (_--)
solve();
return 0;
}