题意:给定一个序列ai,你需要通过下面两个操作让序列中的所有数相等。
1.选中某个数ai, ai = ai * 2
2.选中某个数ai, ai = ai / 2(如3 / 2 = 1)
求使全部数都相等的最小操作数。
分析:这是道BFS,需要对每个数都BFS一下,搜索出这个数所能到达的每个数,累加到cnt[i],下标i表示这个数,\(cnt[i]\)表示被不同的数到达的次数总和,如果这个次数为n,说明每个数都可以变换到这个数,因此可以更新答案。CF对memeset的卡时间非常严格,我们可以用队列存储pair<int, int>,这样就不需要开dist数组了。
和这种题差不多,题目链接。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
using PII = pair<int, int>;
const int N = 200005;
const int inf = 0x3f3f3f3f;
int a[N];
//到达每个数的总操作次数
int num[N];
//这个数被达到的次数
int cnt[N];
bool st[N];
void bfs(int x)
{
memset(st, 0, sizeof st);
queue<PII> q;
q.push({ x, 0 });
++cnt[x];
st[x] = true;
while (q.size())
{
auto t = q.front();
q.pop();
int x = t.first;
int y = t.second;
if ((x << 1) <= 1e5 && !st[x << 1])
{
st[x << 1] = true;
++cnt[x << 1];
q.push({ x << 1, y + 1 });
num[x << 1] += y + 1;
}
if ((x >> 1) >= 1 && !st[x >> 1])
{
st[x >> 1] = true;
++cnt[x >> 1];
q.push({ x >> 1, y + 1 });
num[x >> 1] += y + 1;
}
}
}
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i], bfs(a[i]);
int res = inf;
for (int i = 1; i <= N - 5; ++i)
{
if (cnt[i] == n)
{
res = min(res, num[i]);
//cout << i << endl;
}
}
printf("%d\n", res);
return 0;
}