Codeforces 558C Amr and Chemistry(dp)

来源:互联网 发布:java求职简历自我评价 编辑:程序博客网 时间:2024/06/04 03:53

题意:

给你n个数,让你通过下面两种操作,把它们转换为同一个数。求最少的操作数。
1. ai=ai2
2. ai=ai/2,向下取整

思路:

因为ai<=100000,因此就可以想到通过处理出所有数转到num所需要的最少操作数dp[num],维护dp[num]的最小值即可。对于ai,我们处理出它转换到所有其它数的最少操作数。
先枚举左移,在枚举右移。讲dp[num]的和记录在res[num]数组中表示到达num最少的总操作次数。注意:要满足全部的数字都能满足num,所以要在用一个cnt[num]来记录每个num的出现次数。
所以题意条件的是cnt[num]=n,且res[num]最小的。

my code

#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <cstdlib>using namespace std;typedef long long ll;const int MAXN = (1<<20)+5;const int INF = 0x3f3f3f3f;int cnt[MAXN];bool vis[MAXN];int res[MAXN], dp[MAXN];vector<int> vec;int Scan() {      int res = 0, ch, flag = 0;      if((ch = getchar()) == '-')             //判断正负          flag = 1;      else if(ch >= '0' && ch <= '9')           //得到完整的数          res = ch - '0';      while((ch = getchar()) >= '0' && ch <= '9' )          res = res * 10 + ch - '0';      return flag ? -res : res;  }int main() {    int n, a;    while(scanf("%d", &n) != EOF) {        for(int k = 0; k < n; k++) {            a = Scan();            vec.clear();            int num = MAXN;            for(int i = 0; i <= 20 && num; i++) {                num = (a >> i);                if(num == 0) continue;                for(int j = 0; num < MAXN; num <<= 1, j++) {                    if(!vis[num]) {                        dp[num] = i+j;                        cnt[num]++;                        vis[num] = true;                        vec.push_back(num);                    }else dp[num] = min(dp[num], i+j);                }            }            for(int i = 0; i < vec.size(); i++) {                int tmp = vec[i];                vis[tmp] = false;                res[tmp] += dp[tmp];            }        }        int minv = INF;        for(int i = 0; i < MAXN; i++) {            if(cnt[i] == n)                minv = min(minv, res[i]);            cnt[i] = 0;        }        printf("%d\n", minv);        memset(res, 0, sizeof(res));    }    return 0;}
0 0
原创粉丝点击