51Nod_1483 化学变换
http://www.51nod.com/Challenge/Problem.html#!#problemId=1483
题目
有n种不同的化学试剂。第i种有ai升。每次实验都要把所有的化学试剂混在一起,但是这些试剂的量一定要相等。所以现在的首要任务是把这些化学试剂的量弄成相等。有两种操作:把第i种的量翻倍,即第i种的量变成2ai。把第i种的量减半,除的时候向下取整。现在所有的化学试剂的量已知,问最少要变换多少次,这些化学试剂的量才会相等。样例解释:把8变成4,把2变成4。这样就需要两次就可以了。
输入
单组测试数据。第一行有一个整数n (1 ≤ n ≤ 10^5),表示化学物品的数量。第二行有n个以空格分开的整数ai (1 ≤ ai ≤ 10^5),表示第i种化学试剂的量。
输出
输出一个数字,表示最少的变化次数。
样例输入
3
4 8 2
样例输出
2
分析
枚举每个数能变换成的数,以及变换需要的步数,如果n个数都能变成某个数,更新答案即可,具体看程序。
C++程序
#include<iostream>
using namespace std;
const int N=100005;
int count[N];//count[i]记录能通过乘2或除2变成i的数的个数
int ans[N];//ans[i]统计n个数变成i总共需要的步数
void convert(int n,int step)
{
//乘2
for(int i=n;i<N;i*=2,step++)
{
count[i]++;
ans[i]+=step;
}
}
int main()
{
int n,x,res=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
convert(x,0);
int step=0;
while(x/2>0)
{
if(x%2==1)//如果x是奇数,要考虑x/2 不断乘2的扩展
convert(x/2,++step);
else//如果x是偶数的话就,只用考虑x/2这个数
{
count[x/2]++;
ans[x/2]+=(++step);
}
x/=2;
}
res+=(++step);//统计各个数变成0的步数
}
for(int i=1;i<N;i++)
if(count[i]==n)//如果n个数都能变换为i,则更新答案
res=min(res,ans[i]);
printf("%d\n",res);
return 0;
}