题意:给定一个序列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;
}