码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces 558C Amr and Chemistry(数论+位运算)

时间:2015-07-15 22:55:38      阅读:200      评论:0      收藏:0      [点我收藏+]

标签:codeforces   数论   

C. Amr and Chemistry
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

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

Amr has n different types of chemicals. Each chemical i 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 be 2ai
  • 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 integers ai (1?≤?ai?≤?105), representing the initial volume of the i-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 equal 4.

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 equal 1.

题意:给出n个数,让你通过下面两种操作,把它们转换为同一个数。求最少的操作数。

1.ai = ai*2

2.ai = ai/2,向下取整


思路:可以除以二 或者 乘以二,就相当于位运算的右移和左移。用两个数组,vis 数组, cnt 数组。刚开始都初始化为0; vis[i] 表示 i 这个数可以由几个数转化而来,cnt[i] 表示题目给出的 n 个数全部转化为 i 需要的操作数。

首先遍历数组找到 ai 的最大值记为 MAX,那么所有数转化的上界就是 MAX,因为如果最终转化的数如果大于MAX,那么所有值都要转化为大于MAX的那个数,很明显这不是最后的答案。

把一个数表示为二进制数,

1、如果最低位是0,那么这个数右移一位(除以2),再左移一位(乘以2),就得到原来的数

2、如果最低位是1,那么这个数右移一位(除以2),再左移一位(乘以2),得不到原来的数

那么:

3要转化为8,最少需要4步操作,先除以2,再乘以2,再乘以2,再乘以2

2要转化为8,最少需要2步操作,先乘以2,再乘以2

处理一个数 ai:

1、对 ai 执行左移操作,记录 ai 通过左移能够得到的数字,上限为MAX,vis 数组加1,cnt数组记录步数

2、对 ai 执行右移操作,直到 ai 为0

若 ai 的最低位为1,右移一步之后,进行左移,上限为MAX,维持vis数组和cnt数组

若 ai 的最低位为0,右移一步,维持vis数组和cnt数组

这样我们就把一个数的所有情况都处理出来了,并且是最少的操作数。

最后遍历数组找 vis[i] 为n,并且操作数最小。

<span style="font-size:18px;">#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;

const double PI = acos(-1.0);
const double e = 2.718281828459;
const double eps = 1e-8;
const int MAXN = 100010;
int a[2*MAXN];
int vis[2*MAXN];
int cnt[2*MAXN];
int n;
int MAX = 0;

void solve(int v)
{
    vis[v]++;
    int temp1 = v;
    int temp2 = v;
    int step1 = 0;
    int step2 = 0;
    while(temp1 <= MAX)
    {
        temp1 <<= 1;
        step1++;
        vis[temp1]++;
        cnt[temp1] += step1;
    }
    while(temp2)
    {
        if(temp2&1 && temp2!=1)
        {
            temp2 >>= 1;
            step2++;
            vis[temp2]++;
            cnt[temp2] += step2;
            int temp3 = temp2;
            int step3 = step2;
            while(temp3 <= MAX)
            {
                temp3 <<= 1;
                step3++;
                vis[temp3]++;
                cnt[temp3] += step3;
            }
        }
        else
        {
            temp2 >>= 1;
            step2++;
            vis[temp2]++;
            cnt[temp2] += step2;
        }
    }
}

int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    while(cin>>n)
    {
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &a[i]);
            MAX = max(a[i], MAX);
        }
        memset(vis, 0, sizeof(vis));
        memset(cnt, 0, sizeof(cnt));
        for(int i = 1; i <= n; i++)
            solve(a[i]);
        int ans = 1<<29;
        for(int i = 1; i <= 2*MAX-1; i++)
        {
            if(vis[i] == n)
                ans = min(ans, cnt[i]);
        }
        cout<<ans<<endl;
    }
    return 0;
}

</span>


版权声明:本文为博主原创文章,未经博主允许不得转载。

Codeforces 558C Amr and Chemistry(数论+位运算)

标签:codeforces   数论   

原文地址:http://blog.csdn.net/u014028317/article/details/46897963

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!