Codeforces 558C - Amr and Chemistry (枚举)

枚举每个数乘二和除二过程中所能到达的所有数,并记录到达时的步数,最后统计在所有数都能到达的数字中步数和最小的数字。

因为只有*2和/2的操作,所以往大往小都是log级的。

注意,如果一个数是奇数,那么它本身一直乘二所能到达的数字,和它除2向下取整再一直乘二所能到达的数字是完全不相同的。因为在二进制下除二后相当于左移把末尾的1弄没了,以后再右移时前缀都不一样了。所以在向下除的过程中每次遇到奇数都要处理一下。


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL long long
int n;
LL c[200005];
int b[200005];
int a[100005];

void up(int n,int k){
    if(!n) return ;
    while(n<=200000){
        b[n]++;
        c[n]+=k;
        k++;
        n<<=1;
    }
}


void solve(int n){
    int cur=0;
    LL num=n*2;
    up(num,1);
    num=n;
    cur=0;
    while(num){
        if(num&1){
            up(num/2*2,cur+2);
        }
        b[num]++;
        c[num]+=cur;
        num>>=1;
        cur++;
    }
}



int main(){
    scanf("%d",&n);
    memset(c,0,sizeof(c));
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
        solve(a[i]);
    }
    LL res=1000000000;
    for(int i=0;i<=200000;i++){
        if(b[i]==n){
            res=min(res,c[i]);
        }
    }
    printf("%lld\n",res);
}


你可能感兴趣的:(Codeforces 558C - Amr and Chemistry (枚举))