暴力 + 贪心 --- Codeforces 558C : Amr and Chemistry

 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;
}
/*

*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值