zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    获取小程序码
    获取目标地与当前地距离
    小程序图片预览
    地图导航
    Jquery无缝滚动
    短信验证
    根据经纬度获取地址
    微信小程序中使用emoji表情
    小程序图片上传
    地球人类的牢笼
  • 原文地址:https://www.cnblogs.com/LSlzf/p/11079005.html
Copyright © 2011-2022 走看看