时间限制: 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
题解:
可以发现每次只会被切成两种长度。
CodeCodeCode:
#include<bits/stdc++.h>
using namespace std;
int a[55],tot;
const int inf=1e9+5;
struct node
{
int val,t,fr;
}t[100005];
inline int read()
{
int x=0,f=1;
char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}
return x*f;
}
int cmp(node x,node y)
{
if(x.val==y.val&&x.fr==y.fr)return x.t>y.t;
if(x.val==y.val)return x.fr<y.fr;
return x.val<y.val;
}
int main()
{
int T=read();
while(T--)
{
int n=read();tot=0;
for(int i=1;i<=n;i++)
{
a[i]=read();
int cnt=0;
t[++tot].val=a[i];t[tot].t=0;t[tot].fr=i;
while(a[i]!=1)
{
cnt++;
if(a[i]%2==0)
{
a[i]>>=1;
t[++tot].val=a[i];t[tot].t=cnt;t[tot].fr=i;
}else
{
t[++tot].val=a[i]/2;t[tot].t=cnt;t[tot].fr=i;
t[++tot].val=a[i]-a[i]/2;t[tot].t=cnt;t[tot].fr=i;
if((a[i]/2)%2==1)a[i]=a[i]/2;else
a[i]=a[i]-a[i]/2;
}
}
}
sort(t+1,t+tot+1,cmp);
int k=tot,ans=inf;
for(int j=tot-1;j>=0;j--)
{
if(t[j].val!=t[j+1].val)
{
int cnt=1,sum=t[k].t;
for(int p=k-1;p>=j+1;p--)
if(t[p].fr!=t[p+1].fr)sum+=t[p].t,cnt++;
if(cnt==n)ans=min(ans,sum);
k=j;
}
}
printf("%d\n",ans);
}
return 0;
}