题目链接:http://codeforces.com/problemset/problem/558/C
题意:有n个数,每个数都可以进行两个操作 *2 或者 /2,求最小的操作次数和,使得所有的数都相等;
计算一下时间复杂度可以知道每个数所能达到数的时间复杂度是log(1e5)最终的时间复杂度也就是 nlog(1e5), 所以暴力能过,
刚开始看到的时候一看数据范围就根本不敢暴力了。。。
我们可以把每个数所有变化情况都记录下来,并记录出现的次数,因为只有用1e5的数据量。
先把数据量范围内的所有比a1大的数(a1*2,a1*4。。。)的次数都相对应的加(1,2,。。。)
然后找比a1小的,/2如果遇到奇数,还要接着往上*2.。。
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <math.h> #define N 100100 #define INF 0x3f3f3f3f #define met(a, b) memset(a, b, sizeof(a)) using namespace std; int num[N], cnt[N]; void F(int x) { int step = 0, t = x; cnt[x] ++; while(t*2 < N)///往上*2得到的都是偶数,直接记录; { t = t*2; step ++; num[t] += step; cnt[t] ++; } t = x, step = 0; while(t > 1) { if(t!=1 && t%2==1)///往下/2得到的可能是奇数, 如果是奇数的话继续往上*2; { int y = t/2; int step0 = step+1; while(y*2 < N) { y = y*2; step0 ++; num[y] += step0; cnt[y] ++; } } t = t/2; step ++; num[t] += step; cnt[t] ++; } } int main() { int n, x; while(scanf("%d", &n)!=EOF) { met(cnt, 0); met(num, 0); for(int i=0; i<n; i++) { scanf("%d", &x); F( x ); } int ans = INF; for(int i=0; i<N; i++) { if(n == cnt[i]) ans = min(ans, num[i]); } printf("%d\n", ans); } return 0; }
时间: 2024-10-24 00:15:17