刚刚FST掉,好明显的错误居然过了60+组。。
题意:
给你n个数,让你通过下面两种操作,把它们转换为同一个数。求最少的操作数。
1.ai = ai*2
2.ai = ai/2,向下取整
思路:
看到乘2,除2是不是应该有点感觉。对,就是位的左右移位。
因为ai<= 1e5,因此就可以想到通过处理出所有数转到t所需要的最少操作数cnt[t],最后取cnt的最小值即可。
对于ai,我们处理出它转换到所有其它数的最少操作数。
处理过程:
一开始ai,首先先执行右移,直到1e5。
然后ai重新开始进行左移操作。
1.遇到1(最高位的那个1不用处理),则再左移一位,然后再右移直到1e5。
2.遇到0则继续左移。
这样我们就把一个数的所有情况都处理出来了,并且是最少的操作数。
还有一个vis数组,vis[t]用来保存t能被多少个ai所转移过来的个数。
code:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
const int INF = 0x3f3f3f3f;
typedef long long LL;
int n;
int a[N], cnt[2*N], vis[2*N];
}
void deal(int val) {
int tmp = val, step = 0;
vis[val]++;
int tt = tmp, instep = 0;
while(tt <= (int)1e5) {
tt <<= 1;
instep++;
vis[tt]++;
cnt[tt] += instep;
}
while(tmp) {
if((tmp & 1) && tmp != 1) {
tmp >>= 1;
step++;
cnt[tmp] += step;
vis[tmp]++;
int tt = tmp;
int instep = step;
while(tt <= (int)1e5) {
tt <<= 1;
instep++;
vis[tt]++;
cnt[tt] += instep;
}
}
else {
tmp >>= 1;
step++;
cnt[tmp] += step;
vis[tmp] ++;
}
}
}
void solve() {
for(int i = 0;i < n; i++) deal(a[i]);
int res = INF;
for(int i = 1;i <= (int)2e5; i++)
if(vis[i] == n){
//cout<<i<<" "<<cnt[i]<<endl;
res = min(res, cnt[i]);
}
printf("%d\n", res);
}
int main() {
scanf("%d", &n);
for(int i = 0;i < n; i++) {
scanf("%d" ,&a[i]);
}
solve();
return 0;
}