A
时间限制: 1 Sec 内存限制: 128 MB
题目描述
你有一堆棍子。每个木棒的长度是一个正整数。
你想要一组棍子所有的棍子都有相同的长度。您可以通过执行零个或多个步骤来更改当前集合。每个步骤必须如下所示:
你选择一根棍子。所选棒的长度必须至少为2。设L为所选木棍的长度。
如果L是偶数,把棍子切成两根长度为L/2的棍子。否则,把它切成长度为(L-1)/2和(L+1)/2的棒。把两根新棍子中的一根留下,把另一根扔掉。
可以证明,任何一种集合都可以变成一种长度相同的集合。给定当前棍子集合的长度,计算并返回达到目标所需的最小步骤数。
输入
多组数据,第一行一个整数T,表示数据组数,T<=6
每组数据:
第一行一个整数N,表示棍子数目。(2<=N<=50)
第二行N个整数,a[i]表示第i个棍子的长度。(1<=a[i]<=10^9)
输出
输出达到目标所需的最小步骤数
样例输入
4 2 11 4 4 1000 1000 1000 1000 7 1 2 3 4 5 6 7 6 13 13 7 11 13 11
样例输出
3 0 10 11
大神们手摸了一下就找到规律了
一根木棒切了k次后最多有两根
所以可以记录下来所有的长度
只要有n个就可以当做一个答案
注:当x=5时要特判
因为它可以切出:3,2,2,1,有两个2
#include<cstdio>
#include<algorithm>
using namespace std;
int read()
{
int ret=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9')
ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();
return ret;
}
int n,cnt,num,ans,anss;
int a[2000005],b[105];
bool cmp(int i,int j)
{
return i>j;
}
int main()
{
int T=read();
while(T--)
{
int n=read();
cnt=0;
for(int i=1;i<=n;i++)
{
b[i]=read();
int x=b[i];
a[++cnt]=x;
while(x!=1)
{
if(x==5)
{
a[++cnt]=3,a[++cnt]=2;a[++cnt]=1;
break;
}
if(x&1)
{
a[++cnt]=x>>1,a[++cnt]=(x+1)>>1;
if((x>>1)&1) x>>=1;
else x=(x+1)>>1;
} else a[++cnt]=x>>1,x>>=1;
}
}
sort(a+1,a+cnt+1,cmp);
num=1;ans=0;
for(int i=2;i<=cnt;i++)
if(a[i]==a[i-1]) num++;
else
{
if(num==n)
{
ans=a[i-1]; break;
}
num=1;
}
if(!ans) ans=a[cnt];
anss=0;
for(int i=1;i<=n;i++)
{
while(b[i]!=ans)
{
if(b[i]&1)
{
anss++;
if(((b[i]+1)>>1)==ans||(b[i]>>1)==ans) break;
if((b[i]>>1)&1) b[i]>>=1;
else b[i]=(b[i]+1)>>1;
} else
{
anss++;
if((b[i]>>1)==ans) break;
b[i]>>=1;
}
}
}
printf("%d\n",anss);
}
return 0;
}