C. Amr and Chemistry
Problem's Link: http://codeforces.com/problemset/problem/558/C
Mean:
给出n个数,让你通过下面两种操作,把它们转换为同一个数。求最少的操作数。
1.ai = ai*2
2.ai = ai/2 (向下取整)
analyse:
基本思路:首先枚举出每个数能够到达的数字并且记录下到达该数组需要的步数,然后从到达次数为n次的数字中选择步数最小的即为答案。
对于一个数字Ai,它可以变换得到的数字可以分为三类:
1.向左移动n位得到的数字;
2.向右移动n位得到的数字;
3.奇数/2后得到的偶数向右移动n位得到的数字。
处理一个数 Ai:
1、对 Ai 执行左移操作,记录 Ai 通过左移能够得到的数字,上限为1e5,vis 数组加1,cnt数组记录步数
2、对 Ai 执行右移操作,直到 Ai 为0.
若 Ai 的最低位为1,右移一步之后,进行左移,上限为1e5,维持vis数组和cnt数组.
若 Ai 的最低位为0,右移一步,维持vis数组和cnt数组.
这样我们就把一个数的所有情况都处理出来了,并且是最少的操作数.
最后遍历数组找 vis[i] 为n,并且操作数最小。
Time complexity: O(n*m*log(MAX))
Source code:
/* * this code is made by crazyacking * Verdict: Accepted * Submission Date: 2015-07-15-18.53 * Time: 0MS * Memory: 137KB */ #include <queue> #include <cstdio> #include <set> #include <string> #include <stack> #include <cmath> #include <climits> #include <map> #include <cstdlib> #include <iostream> #include <vector> #include <algorithm> #include <cstring> #define LL long long #define ULL unsigned long long using namespace std; const int MAXN(10+int(1e5)); int arrive_step[MAXN<<1]; int arrive_num[MAXN<<1]; int a[MAXN],n; void init() { for(int i=0; i<MAXN<<1; ++i) { arrive_step[i]=0,arrive_num[i]=0; } } inline void count_arrive(int &x) { int t=x,step=0; arrive_num[t]++; while(t<=int(1e5)) { t<<=1; step++; arrive_step[t]+=step; arrive_num[t]++; } t=x,step=0; while(t>1) { if(t!=1 && (t&1)) { int sta=t>>1; int sstep=step+1; while(sta<=int(1e5)) { sta<<=1; sstep++; arrive_step[sta]+=sstep; arrive_num[sta]++; } } t>>=1; step++; arrive_step[t]+=step; arrive_num[t]++; } } int main() { ios_base::sync_with_stdio(false); cin.tie(0); while(~scanf("%d",&n)) { init(); for(int i=0; i<n; ++i) { scanf("%d",&a[i]); count_arrive(a[i]); } int ans=INT_MAX; for(int i=1; i<(MAXN<<1); ++i) { if(arrive_num[i]==n) ans=ans<arrive_step[i]?ans:arrive_step[i]; } printf("%d\n",ans); } return 0; } /* */