枚举每个数乘二和除二过程中所能到达的所有数,并记录到达时的步数,最后统计在所有数都能到达的数字中步数和最小的数字。
因为只有*2和/2的操作,所以往大往小都是log级的。
注意,如果一个数是奇数,那么它本身一直乘二所能到达的数字,和它除2向下取整再一直乘二所能到达的数字是完全不相同的。因为在二进制下除二后相当于左移把末尾的1弄没了,以后再右移时前缀都不一样了。所以在向下除的过程中每次遇到奇数都要处理一下。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL long long
int n;
LL c[200005];
int b[200005];
int a[100005];
void up(int n,int k){
if(!n) return ;
while(n<=200000){
b[n]++;
c[n]+=k;
k++;
n<<=1;
}
}
void solve(int n){
int cur=0;
LL num=n*2;
up(num,1);
num=n;
cur=0;
while(num){
if(num&1){
up(num/2*2,cur+2);
}
b[num]++;
c[num]+=cur;
num>>=1;
cur++;
}
}
int main(){
scanf("%d",&n);
memset(c,0,sizeof(c));
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
solve(a[i]);
}
LL res=1000000000;
for(int i=0;i<=200000;i++){
if(b[i]==n){
res=min(res,c[i]);
}
}
printf("%lld\n",res);
}