题目描述

你有一堆棍子。每个木棒的长度是一个正整数。

你想要一组棍子所有的棍子都有相同的长度。您可以通过执行零个或多个步骤来更改当前集合。每个步骤必须如下所示:

你选择一根棍子。所选棒的长度必须至少为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

Solution

这道题需要注意的是当棍子长度是奇数的时候情况是不唯一的;

这样如果存储所有可能的状态是 \(2^30\) 级别的, 显然不能承受.

但是我们发现一个 性质 : 对于一个长度是奇数的棍子, 执行 k 次操作的可能长度只有 2 种, 这是因为当一个奇数被分成 奇数+偶数 时, 偶数接下来的所有情况都会被包含在奇数里. 所以偶数往下延伸的情况是没有必要的,每一层只有 1 个节点会往后延伸, 每一层最多只有 2 个节点.

这有点像线段树的性质.

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
 
int n, step[55][31][2], maxstep[55];
 
inline int solve(int len){
    int ans = 0;
    for (int i = 1; i <= n; ++i){
        bool check = false;
        for (int j = 0; j <= 30; ++j)
            if (step[i][j][0] == len || step[i][j][1] == len){
                ans += j;
                check = true;
                break;
            }
        if (!check) return 100000000;
    }
    return ans;
}
 
int main(){
    int T; scanf("%d", &T);
    while (T--){
        scanf("%d", &n); memset(step, 0, sizeof(step));
        for (int i = 1; i <= n; ++i){
            scanf("%d", &step[i][0][0]);
            maxstep[i] = 0; int x = step[i][0][0];
            while (x > 1){
                ++maxstep[i];
                if (x % 2 == 0) step[i][maxstep[i]][0] = x / 2, x = x / 2;
                else{
                    step[i][maxstep[i]][0] = (x-1) / 2;
                    step[i][maxstep[i]][1] = (x+1) / 2;
                    if (x % 4 == 1) x = (x+1) / 2;
                    else x = (x-1) / 2;
                }
            }
        }
 
        /*for (int i = 1; i <= n; ++i)
            for (int j = 0; j <= maxstep[i]; ++j)
                printf("(%d,%d)%c", step[i][j][0], step[i][j][1], (j < maxstep[i]) ? ' ' : '\n');*/
         
        int Ans = 100000000;
 
        for (int i = 0; i <= maxstep[1]; ++i){
            for (int j = 0; j <= 1; ++j)
                if (step[1][i][j]){
                    Ans = min(Ans, solve(step[1][i][j]));
                }
        }
 
        printf("%d\n", Ans);
    }
    return 0;
}

最新文章

  1. 重构sql server的sys.sp_helptext存储
  2. 使用nginx-http-concat添加nginx资源请求合并功能
  3. ASP.NET 服务器控件的生命周期
  4. hadoop: hdfs API示例
  5. ie6下absolute:fixed问题,完美兼容
  6. sqlserver卡号段分组
  7. Java与正则表达式
  8. Delphi与Qt在Windows下使用共享内存进程间通信
  9. HDU 5696 区间的价值 暴力
  10. iOS给背景添加点击事件
  11. [个人翻译]Redis 集群教程(下)
  12. jQuery的标签选择器$(&#39;p&#39;)、类选择器$(&#39;.myClass&#39;)、id选择器$(&#39;#myId&#39;)
  13. [bzoj4866] [Ynoi2017]由乃的商场之旅
  14. TFS Release 步骤调用命令行返回失败信息的处理方法
  15. 最全的MonkeyRunner自动化测试从入门到精通(3)
  16. python 全栈开发,Day115(urlencode,批量操作,快速搜索,保留原搜索条件,自定义分页,拆分代码)
  17. java 代码块,静态代码块,构造器等的执行顺序
  18. Direct2D教程VI——转换(Transform)
  19. ABBYY FineReader 12没你想得那么简单
  20. [js]js中原型的继承

热门文章

  1. lombok系列(一)
  2. kubernetes云平台管理实战: 最小的资源pod(二)
  3. Java虚拟机垃圾回收(三) 7种垃圾收集器
  4. excel转换为TXT文本
  5. ConcurrentLinkedQueue使用和方法介绍
  6. 拖动DIV
  7. Tupper自我指涉公式生成器
  8. Java 自定义hashmap和hashtable的key注意哪些问题
  9. liblensfun 在 mingw 上编译时遇到的奇怪问题
  10. 【原创】大数据基础之Zookeeper(1)介绍、安装及使用