题目大意:给出n个数,每次操作可以对其中一个数进行乘以2操作或者除以2操作,求将n个数变成同一个数所需要的最少的操作步数
解题思路:乘以2/除以2,相当于右移/左移,对于每个数枚举其可以变成的数及其最小步数,最后再看是否所有的数都能变成该数,再比较是否为最小的。在枚举的过程中,需要注意一直左移可得到比其大的数,右移过程中若遇到奇数,就需要将其减去1的数进行左移,那些数也是可以由该数变成的,另,需要注意右移的过程中,需要从本身开始,遇到奇数执行减1左移操作
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+100;
int a[maxn],res[maxn],vis[maxn];
int main()
{
int n;
while(scanf("%d",&n) != EOF)
{
memset(res,0,sizeof(res));
memset(vis,0,sizeof(vis));
int maxx = 0;
for(int i = 0; i < n; i++)
{
scanf("%d",&a[i]);
maxx = max(maxx,a[i]);
}
for(int i = 0; i < n; i++)
{
int cnt = 1;
for(int j = a[i]<<1; j <= maxx; j <<= 1)
{
vis[j]++;
res[j] += cnt;
cnt++;
}
cnt = 0;
for(int j = a[i]; j >= 1; j >>= 1)
{
vis[j]++;
res[j] += cnt;
cnt++;
if(j&1 && j != 1)
{
int cntt = cnt+1;
for(int k = j-1; k <= maxx; k <<= 1)
{
vis[k]++;
res[k] += cntt;
cntt++;
}
}
}
}
int minn = 0xffffff;
for(int i = 1; i <= maxx; i++)
if(vis[i]==n)
minn = min(minn,res[i]);
printf("%d\n",minn);
}
return 0;
}