标签:codeforces 数论
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.
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?
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 one integer the minimum number of operations required to make all the chemicals volumes equal.
3
4 8 2
2
3
3 5 6
5
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