化学变换 51Nod - 1483

有n种不同的化学试剂。第i种有ai升。每次实验都要把所有的化学试剂混在一起,但是这些试剂的量一定要相等。所以现在的首要任务是把这些化学试剂的量弄成相等。

有两种操作:

・        把第i种的量翻倍,即第i种的量变成2ai。

・        把第i种的量减半,除的时候向下取整,即把第i种的量变成  ai2 

 。

现在所有的化学试剂的量已知,问最少要变换多少次,这些化学试剂的量才会相等。

样例解释:把8变成4,把2变成4。这样就需要两次就可以了。


Input
单组测试数据。
第一行有一个整数n (1 ≤ n ≤ 10^5),表示化学物品的数量。
第二行有n个以空格分开的整数ai (1 ≤ ai ≤ 10^5),表示第i种化学试剂的量。
Output
输出一个数字,表示最少的变化次数。
Sample Input
3
4 8 2
Sample Output
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;
    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值