topcoder div 1(1)

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;
}

猜你喜欢

转载自blog.csdn.net/YYHS_WSF/article/details/82880783