A

本文探讨了一个算法问题,即如何通过切割和丢弃部分的方式,将一堆长度不一的棍子转化为所有棍子长度相等的集合,同时计算达到这一目标所需的最小步骤数。文章提供了一种解决方案,并附带了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

时间限制: 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; 
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JackflyDC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值