给大家一种好理解的做法吧
简化题意:每个数都可以进行若干次除2的操作,最终需要使所有数相同,输出最少的操作次数
我们可以发现,对一个数进行 i 次除2,等效于在将其二进制右移 i 位,而一个 1e9范围内 的数通过除2能得到的数,最多只有29个,我可以轻松的维护出每个数 x 右移 i 位得到的数 y
那我们回到题目,最终要求所有数相同,也就是说所有的数都需要有一个相同的最终状态 Y ,所以我们可以在之前维护 y 的时候将其的权值加一,表示能到达 y 这个状态的数的个数,顺便维护一下当前的 x 到达 y 这个状态需要的步数,也就是 i ,对于每个 y ,我们维护一个 pair<int,int> ,first 表示能到达 y 这个状态的数的个数,second 表示每个数到达 y 这个状态需要的步数,很明显,如果 first == n ,那么答案就是 second
然后回到题目,要找到最小的 second ,对于所有 first == n 的 y ,一定是 y 最大的那个 second 最小,所以我们可以用一个 map<int,pair<int,int>,greater<int>> 来维护这个信息,方便在后面直接使用 auto [k,v] : mp 来从大到小遍历
#include <bits/stdc++.h> using namespace std; #define int long long const int N = 2e5 + 5; int __t = 1, n, x; void solve() { cin >> n; map<int, pair<int, int>, greater<int>> mp; for (int i = 1; i <= n; i++) { cin >> x; for (int i = 0; x >> i; i++) { mp[x >> i].first++; mp[x >> i].second += i; } } for (auto [k, v] : mp) { if (v.first == n) { cout << v.second << '\n'; return; } } return; } int32_t main() { #ifdef ONLINE_JUDGE ios::sync_with_stdio(false); cin.tie(0); #endif // cin >> __t; while (__t--) solve(); return 0; }