• Test 6.24 T2 集合


    问题描述

    有一个可重集合,一开始只有一个元素 0。
    你可以进行若干轮操作,每轮你需要对集合中每个元素 x 执行以下三种操作之一:

    1. 将 x 变为 x+1;
    2. 选择两个非负整数 y,z 满足 y+z=x ,将 x 变为这两个元素;
    3. 什么都不做。

    给出一个最终的集合,求至少经过几轮才能得到这个集合。

    输入格式

    第一行一个正整数 n,表示最终集合的大小。
    第二行 n 个非负整数 ai,表示最终集合中的元素。

    输出格式

    输出一个整数,表示答案。

    样例输入

    5
    0 0 0 3 3

    样例输出

    解析

    不妨倒过来思考,考虑如何通过将一个数减一和合并两个数使目标集合变成只有0的集合。对于任意两个数(a)(b),如果将两个数分开减为0再合并,那么操作次数为(max(a,b)+1),而先合并再减小为0的操作次数为(a+b+1)。显然第一种更优。推广开来,我们的最优策略即为每轮先和并所有的0,再把不是0的减1,直到只剩一个0为止。

    具体实现也很简单。每次把0的数量减半,同时减小长度。预处理每个数在哪一轮会减为0,并在那一轮最后加上新的0的个数。

    代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #define N 1000002
    using namespace std;
    int n,i,a[N],cnt[N],num,ans;
    int main()
    {
    	freopen("set.in","r",stdin);
    	freopen("set.out","w",stdout);
    	cin>>n;
    	for(i=1;i<=n;i++) cin>>a[i];
    	for(i=1;i<=n;i++) cnt[a[i]]++;
    	num=cnt[0];
    	while(n>1){
    		ans++;
    		n-=num/2;
    		num=(num+1)/2;
    		num+=cnt[ans];
    	}
    	cout<<ans<<endl;
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
    
  • 相关阅读:
    设计模式_享元设计模式(flyweight)
    eclipse的使用
    Bank项目
    反射练习
    反射接口
    反射
    32-一笔画(欧拉图)
    67-蓝桥省赛-2014
    13-STL-二分查找
    31-最长公共子序列
  • 原文地址:https://www.cnblogs.com/LSlzf/p/11079005.html
Copyright © 2020-2023  润新知