有n种不同的化学试剂。第i种有ai升。每次实验都要把所有的化学试剂混在一起,但是这些试剂的量一定要相等。所以现在的首要任务是把这些化学试剂的量弄成相等。
有两种操作:
・ 把第i种的量翻倍,即第i种的量变成2ai。
・ 把第i种的量减半,除的时候向下取整,即把第i种的量变成 ⌊ ai2 ⌋
。
现在所有的化学试剂的量已知,问最少要变换多少次,这些化学试剂的量才会相等。
样例解释:把8变成4,把2变成4。这样就需要两次就可以了。
第一行有一个整数n (1 ≤ n ≤ 10^5),表示化学物品的数量。
第二行有n个以空格分开的整数ai (1 ≤ ai ≤ 10^5),表示第i种化学试剂的量。
3 4 8 2
2
这道题一开始想用广搜可是记录状态是很愁人的一件事,由于数量过多,而且没有关系。所以我想到了二分,但是还是得去找,当然也许是可以的。我们可以直接来把每个点能够到的点都记录下来,最后看一下到底是那个高度最低。当然有一些特殊情况,比如说 10 5 (2 4 8 ...)1,这种情况我们需要注意
#include<stdio.h>
#include<cmath>
#include<algorithm>
#include<cstring>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1e5+10;
int val[maxn];
int dis[maxn*5];
int vis[maxn*5];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&val[i]);
int up_val,down_val;
up_val=down_val=val[i];
vis[val[i]]++;
int up_step=0;
while(up_val<=maxn)
{
up_val *= 2;
vis[up_val]++;
up_step++;
dis[up_val] += up_step;
}
int down_step=0;
while(down_val>1)
{
if(down_val&1)
{
down_val /= 2;
vis[down_val]++;
down_step++;
dis[down_val] += down_step;
int now=down_val;
int temp_step=0;
while(now<=maxn)
{
now *= 2;
vis[now]++;
temp_step++;
dis[now] += temp_step+down_step;
}
}
else
{
down_val /= 2;
vis[down_val]++;
down_step++;
dis[down_val] += down_step;
}
}
}
int ans=INF;
for(int i=1;i<=maxn;i++)
{
if(vis[i]>=n)
ans=min(ans,dis[i]);
}
printf("%d\n",ans);
return 0;
}