codeforcesC. Amr and Chemistry

C. Amr and Chemistry

Amr loves Chemistry, and specially doing experiments. He is preparing for a new interesting experiment.

Amr has n different types of chemicals. Each chemicali has an initial volume of ai liters. For this experiment, Amr has to mix all the chemicals together, but all the chemicals volumes must be equal first. So his task is to make all the chemicals volumes equal.

To do this, Amr can do two different kind of operations.

  • Choose some chemical i and double its current volume so the new volume will be2ai
  • Choose some chemical i and divide its volume by two (integer division) so the new volume will be

Suppose that each chemical is contained in a vessel of infinite volume. Now Amr wonders what is the minimum number of operations required to make all the chemicals volumes equal?

Input

The first line contains one number n (1 ≤ n ≤ 105), the number of chemicals.

The second line contains n space separated integersai (1 ≤ ai ≤ 105), representing the initial volume of thei-th chemical in liters.

Output

Output one integer the minimum number of operations required to make all the chemicals volumes equal.

Sample test(s)
Input
3
4 8 2
Output
2
Input
3
3 5 6
Output
5
Note

In the first sample test, the optimal solution is to divide the second chemical volume by two, and multiply the third chemical volume by two to make all the volumes equal4.

In the second sample test, the optimal solution is to divide the first chemical volume by two, and divide the second and the third chemical volumes by two twice to make all the volumes equal1.



看了官方题解才会写。。。

#include<map>
#include<vector>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<stack>
#include<queue>
#include<set>
#define inf 0x3f3f3f3f
#define mem(a,x) memset(a,x,sizeof(a))

using namespace std;

typedef long long ll;
typedef pair<int,int> pii;

inline int in()
{
    int res=0;char c;
    while((c=getchar())<'0' || c>'9');
    while(c>='0' && c<='9')res=res*10+c-'0',c=getchar();
    return res;
}
int vis[100010];
int cnt[100010];
int step[100010];
queue<pii> q;
int main()
{
    int n=in();
    for(int i=1;i<=n;i++)
    {
        int tmp=in();
        q.push(pii(tmp,0));//0表示tmp到pii.first的操作步数
        while(!q.empty())
        {
            pii now=q.front();
            q.pop();
            int x=now.first;
            int y=now.second;
            if(x>100001)continue;   //上限不超过十万 下限就是0了
            if(vis[x]==i)continue; //vis数组标记有没有被访问过
            vis[x]=i;               /*vis[x]=i用的很巧妙,i是不断变动的,避免了每次都给vis数组全部初始化,注意i应该从1开始,从0开始会导致标记错乱,因为数组中初始为0*/
            cnt[x]++;
            step[x]+=y;
            q.push(pii(x*2,y+1));   //把x不断乘二入队,有上限限制,复杂度是log的
            q.push(pii(x/2,y+1));    //把x不断除二入队,复杂度logx
        }
    }
    int ans=inf;
    for(int i=0;i<=100000;i++)
    {
        if(cnt[i]==n)
        {
            ans=min(ans,step[i]);
        }
    }
    printf("%d\n",ans);

    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值